Merge #1458
1458: rp: remove take!, add bind_interrupts! r=Dirbaio a=pennae both of the uart interrupts now check a flag that only the dma rx path ever sets (and now unsets again on drop) to return early if it's not as they expect. this is ... not our preferred solution, but if bind_interrupts *must* allow mutiple handlers to be specified then this is the only way we can think of that doesn't break uarts. Co-authored-by: pennae <github@quasiparticle.net>
This commit is contained in:
commit
1a87f7477a
@ -3,12 +3,12 @@ use core::marker::PhantomData;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_common::into_ref;
|
use embassy_cortex_m::interrupt::{Binding, Interrupt};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embedded_hal_02::adc::{Channel, OneShot};
|
use embedded_hal_02::adc::{Channel, OneShot};
|
||||||
|
|
||||||
use crate::gpio::Pin;
|
use crate::gpio::Pin;
|
||||||
use crate::interrupt::{self, InterruptExt};
|
use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO};
|
||||||
use crate::peripherals::ADC;
|
use crate::peripherals::ADC;
|
||||||
use crate::{pac, peripherals, Peripheral};
|
use crate::{pac, peripherals, Peripheral};
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
@ -47,10 +47,9 @@ impl<'d> Adc<'d> {
|
|||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_inner: impl Peripheral<P = ADC> + 'd,
|
_inner: impl Peripheral<P = ADC> + 'd,
|
||||||
irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd,
|
_irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>,
|
||||||
_config: Config,
|
_config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let reset = Self::reset();
|
let reset = Self::reset();
|
||||||
crate::reset::reset(reset);
|
crate::reset::reset(reset);
|
||||||
@ -63,14 +62,10 @@ impl<'d> Adc<'d> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup IRQ
|
// Setup IRQ
|
||||||
irq.disable();
|
unsafe {
|
||||||
irq.set_handler(|_| unsafe {
|
ADC_IRQ_FIFO::steal().unpend();
|
||||||
let r = Self::regs();
|
ADC_IRQ_FIFO::steal().enable();
|
||||||
r.inte().write(|w| w.set_fifo(false));
|
};
|
||||||
WAKER.wake();
|
|
||||||
});
|
|
||||||
irq.unpend();
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { phantom: PhantomData }
|
||||||
}
|
}
|
||||||
@ -165,6 +160,18 @@ macro_rules! impl_pin {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InterruptHandler {
|
||||||
|
_empty: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let r = Adc::regs();
|
||||||
|
r.inte().write(|w| w.set_fifo(false));
|
||||||
|
WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_pin!(PIN_26, 0);
|
impl_pin!(PIN_26, 0);
|
||||||
impl_pin!(PIN_27, 1);
|
impl_pin!(PIN_27, 1);
|
||||||
impl_pin!(PIN_28, 2);
|
impl_pin!(PIN_28, 2);
|
||||||
|
@ -2,7 +2,7 @@ use core::future;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::InterruptExt;
|
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use pac::i2c;
|
use pac::i2c;
|
||||||
@ -75,23 +75,21 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(scl, sda, irq);
|
into_ref!(scl, sda);
|
||||||
|
|
||||||
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
|
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let i2c = T::regs();
|
let i2c = T::regs();
|
||||||
|
|
||||||
// mask everything initially
|
// mask everything initially
|
||||||
i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
|
i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
|
||||||
|
T::Interrupt::steal().unpend();
|
||||||
|
T::Interrupt::steal().enable();
|
||||||
}
|
}
|
||||||
irq.unpend();
|
|
||||||
debug_assert!(!irq.is_pending());
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
i2c
|
i2c
|
||||||
}
|
}
|
||||||
@ -115,14 +113,6 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mask interrupts and wake any task waiting for this interrupt
|
|
||||||
unsafe fn on_interrupt(_: *mut ()) {
|
|
||||||
let i2c = T::regs();
|
|
||||||
i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
|
|
||||||
|
|
||||||
T::waker().wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
|
async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
|
||||||
if buffer.is_empty() {
|
if buffer.is_empty() {
|
||||||
return Err(Error::InvalidReadBufferLength);
|
return Err(Error::InvalidReadBufferLength);
|
||||||
@ -320,6 +310,20 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_uart: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
// Mask interrupts and wake any task waiting for this interrupt
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let i2c = T::regs();
|
||||||
|
i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
|
||||||
|
|
||||||
|
T::waker().wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
//! Interrupt management
|
//! Interrupt definitions and macros to bind them.
|
||||||
//!
|
pub use cortex_m::interrupt::{CriticalSection, Mutex};
|
||||||
//! This module implements an API for managing interrupts compatible with
|
|
||||||
//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time.
|
|
||||||
|
|
||||||
// Re-exports
|
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
use embassy_cortex_m::interrupt::_export::declare;
|
||||||
pub use embassy_cortex_m::interrupt::*;
|
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
|
||||||
|
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
use crate::pac::Interrupt as InterruptEnum;
|
||||||
declare!(TIMER_IRQ_0);
|
declare!(TIMER_IRQ_0);
|
||||||
@ -40,3 +36,30 @@ declare!(SWI_IRQ_2);
|
|||||||
declare!(SWI_IRQ_3);
|
declare!(SWI_IRQ_3);
|
||||||
declare!(SWI_IRQ_4);
|
declare!(SWI_IRQ_4);
|
||||||
declare!(SWI_IRQ_5);
|
declare!(SWI_IRQ_5);
|
||||||
|
|
||||||
|
/// Macro to bind interrupts to handlers.
|
||||||
|
///
|
||||||
|
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
||||||
|
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
||||||
|
/// prove at compile-time that the right interrupts have been bound.
|
||||||
|
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bind_interrupts {
|
||||||
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
|
$vis struct $name;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn $irq() {
|
||||||
|
$(
|
||||||
|
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
|
||||||
|
)*
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use core::slice;
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU8, Ordering};
|
use atomic_polyfill::{AtomicU8, Ordering};
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
||||||
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
@ -52,7 +52,7 @@ pub struct BufferedUartTx<'d, T: Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
||||||
irq: PeripheralRef<'d, T::Interrupt>,
|
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
) {
|
) {
|
||||||
@ -79,24 +79,23 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
|||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
w.set_txim(true);
|
w.set_txim(true);
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
irq.set_handler(on_interrupt::<T>);
|
T::Interrupt::steal().unpend();
|
||||||
irq.unpend();
|
T::Interrupt::steal().enable();
|
||||||
irq.enable();
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUart<'d, T> {
|
impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, tx, rx);
|
into_ref!(tx, rx);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config);
|
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config);
|
||||||
init_buffers::<T>(irq, tx_buffer, rx_buffer);
|
init_buffers::<T>(irq, tx_buffer, rx_buffer);
|
||||||
@ -109,7 +108,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
|
|||||||
|
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||||
@ -118,7 +117,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
|
|||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, tx, rx, cts, rts);
|
into_ref!(tx, rx, cts, rts);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(
|
super::Uart::<'d, T, Async>::init(
|
||||||
Some(tx.map_into()),
|
Some(tx.map_into()),
|
||||||
@ -163,12 +162,12 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
|
|||||||
impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, rx);
|
into_ref!(rx);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
|
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
|
||||||
init_buffers::<T>(irq, &mut [], rx_buffer);
|
init_buffers::<T>(irq, &mut [], rx_buffer);
|
||||||
@ -178,13 +177,13 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
|
|
||||||
pub fn new_with_rts(
|
pub fn new_with_rts(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, rx, rts);
|
into_ref!(rx, rts);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config);
|
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config);
|
||||||
init_buffers::<T>(irq, &mut [], rx_buffer);
|
init_buffers::<T>(irq, &mut [], rx_buffer);
|
||||||
@ -312,12 +311,12 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, tx);
|
into_ref!(tx);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
|
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
|
||||||
init_buffers::<T>(irq, tx_buffer, &mut []);
|
init_buffers::<T>(irq, tx_buffer, &mut []);
|
||||||
@ -327,13 +326,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
|
|
||||||
pub fn new_with_cts(
|
pub fn new_with_cts(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq, tx, cts);
|
into_ref!(tx, cts);
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config);
|
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config);
|
||||||
init_buffers::<T>(irq, tx_buffer, &mut []);
|
init_buffers::<T>(irq, tx_buffer, &mut []);
|
||||||
@ -482,97 +481,107 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
|
pub struct BufferedInterruptHandler<T: Instance> {
|
||||||
let r = T::regs();
|
_uart: PhantomData<T>,
|
||||||
let s = T::buffered_state();
|
}
|
||||||
|
|
||||||
unsafe {
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
||||||
// Clear TX and error interrupt flags
|
unsafe fn on_interrupt() {
|
||||||
// RX interrupt flags are cleared by reading from the FIFO.
|
let r = T::regs();
|
||||||
let ris = r.uartris().read();
|
if r.uartdmacr().read().rxdmae() {
|
||||||
r.uarticr().write(|w| {
|
return;
|
||||||
w.set_txic(ris.txris());
|
|
||||||
w.set_feic(ris.feris());
|
|
||||||
w.set_peic(ris.peris());
|
|
||||||
w.set_beic(ris.beris());
|
|
||||||
w.set_oeic(ris.oeris());
|
|
||||||
});
|
|
||||||
|
|
||||||
trace!("on_interrupt ris={:#X}", ris.0);
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
if ris.feris() {
|
|
||||||
warn!("Framing error");
|
|
||||||
}
|
|
||||||
if ris.peris() {
|
|
||||||
warn!("Parity error");
|
|
||||||
}
|
|
||||||
if ris.beris() {
|
|
||||||
warn!("Break error");
|
|
||||||
}
|
|
||||||
if ris.oeris() {
|
|
||||||
warn!("Overrun error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RX
|
let s = T::buffered_state();
|
||||||
let mut rx_writer = s.rx_buf.writer();
|
|
||||||
let rx_buf = rx_writer.push_slice();
|
unsafe {
|
||||||
let mut n_read = 0;
|
// Clear TX and error interrupt flags
|
||||||
let mut error = false;
|
// RX interrupt flags are cleared by reading from the FIFO.
|
||||||
for rx_byte in rx_buf {
|
let ris = r.uartris().read();
|
||||||
if r.uartfr().read().rxfe() {
|
r.uarticr().write(|w| {
|
||||||
break;
|
w.set_txic(ris.txris());
|
||||||
}
|
w.set_feic(ris.feris());
|
||||||
let dr = r.uartdr().read();
|
w.set_peic(ris.peris());
|
||||||
if (dr.0 >> 8) != 0 {
|
w.set_beic(ris.beris());
|
||||||
s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
|
w.set_oeic(ris.oeris());
|
||||||
error = true;
|
|
||||||
// only fill the buffer with valid characters. the current character is fine
|
|
||||||
// if the error is an overrun, but if we add it to the buffer we'll report
|
|
||||||
// the overrun one character too late. drop it instead and pretend we were
|
|
||||||
// a bit slower at draining the rx fifo than we actually were.
|
|
||||||
// this is consistent with blocking uart error reporting.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*rx_byte = dr.data();
|
|
||||||
n_read += 1;
|
|
||||||
}
|
|
||||||
if n_read > 0 {
|
|
||||||
rx_writer.push_done(n_read);
|
|
||||||
s.rx_waker.wake();
|
|
||||||
} else if error {
|
|
||||||
s.rx_waker.wake();
|
|
||||||
}
|
|
||||||
// Disable any further RX interrupts when the buffer becomes full or
|
|
||||||
// errors have occurred. This lets us buffer additional errors in the
|
|
||||||
// fifo without needing more error storage locations, and most applications
|
|
||||||
// will want to do a full reset of their uart state anyway once an error
|
|
||||||
// has happened.
|
|
||||||
if s.rx_buf.is_full() || error {
|
|
||||||
r.uartimsc().write_clear(|w| {
|
|
||||||
w.set_rxim(true);
|
|
||||||
w.set_rtim(true);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// TX
|
trace!("on_interrupt ris={:#X}", ris.0);
|
||||||
let mut tx_reader = s.tx_buf.reader();
|
|
||||||
let tx_buf = tx_reader.pop_slice();
|
// Errors
|
||||||
let mut n_written = 0;
|
if ris.feris() {
|
||||||
for tx_byte in tx_buf.iter_mut() {
|
warn!("Framing error");
|
||||||
if r.uartfr().read().txff() {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
r.uartdr().write(|w| w.set_data(*tx_byte));
|
if ris.peris() {
|
||||||
n_written += 1;
|
warn!("Parity error");
|
||||||
|
}
|
||||||
|
if ris.beris() {
|
||||||
|
warn!("Break error");
|
||||||
|
}
|
||||||
|
if ris.oeris() {
|
||||||
|
warn!("Overrun error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// RX
|
||||||
|
let mut rx_writer = s.rx_buf.writer();
|
||||||
|
let rx_buf = rx_writer.push_slice();
|
||||||
|
let mut n_read = 0;
|
||||||
|
let mut error = false;
|
||||||
|
for rx_byte in rx_buf {
|
||||||
|
if r.uartfr().read().rxfe() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let dr = r.uartdr().read();
|
||||||
|
if (dr.0 >> 8) != 0 {
|
||||||
|
s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
|
||||||
|
error = true;
|
||||||
|
// only fill the buffer with valid characters. the current character is fine
|
||||||
|
// if the error is an overrun, but if we add it to the buffer we'll report
|
||||||
|
// the overrun one character too late. drop it instead and pretend we were
|
||||||
|
// a bit slower at draining the rx fifo than we actually were.
|
||||||
|
// this is consistent with blocking uart error reporting.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*rx_byte = dr.data();
|
||||||
|
n_read += 1;
|
||||||
|
}
|
||||||
|
if n_read > 0 {
|
||||||
|
rx_writer.push_done(n_read);
|
||||||
|
s.rx_waker.wake();
|
||||||
|
} else if error {
|
||||||
|
s.rx_waker.wake();
|
||||||
|
}
|
||||||
|
// Disable any further RX interrupts when the buffer becomes full or
|
||||||
|
// errors have occurred. This lets us buffer additional errors in the
|
||||||
|
// fifo without needing more error storage locations, and most applications
|
||||||
|
// will want to do a full reset of their uart state anyway once an error
|
||||||
|
// has happened.
|
||||||
|
if s.rx_buf.is_full() || error {
|
||||||
|
r.uartimsc().write_clear(|w| {
|
||||||
|
w.set_rxim(true);
|
||||||
|
w.set_rtim(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TX
|
||||||
|
let mut tx_reader = s.tx_buf.reader();
|
||||||
|
let tx_buf = tx_reader.pop_slice();
|
||||||
|
let mut n_written = 0;
|
||||||
|
for tx_byte in tx_buf.iter_mut() {
|
||||||
|
if r.uartfr().read().txff() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r.uartdr().write(|w| w.set_data(*tx_byte));
|
||||||
|
n_written += 1;
|
||||||
|
}
|
||||||
|
if n_written > 0 {
|
||||||
|
tx_reader.pop_done(n_written);
|
||||||
|
s.tx_waker.wake();
|
||||||
|
}
|
||||||
|
// The TX interrupt only triggers once when the FIFO threshold is
|
||||||
|
// crossed. No need to disable it when the buffer becomes empty
|
||||||
|
// as it does re-trigger anymore once we have cleared it.
|
||||||
}
|
}
|
||||||
if n_written > 0 {
|
|
||||||
tx_reader.pop_done(n_written);
|
|
||||||
s.tx_waker.wake();
|
|
||||||
}
|
|
||||||
// The TX interrupt only triggers once when the FIFO threshold is
|
|
||||||
// crossed. No need to disable it when the buffer becomes empty
|
|
||||||
// as it does re-trigger anymore once we have cleared it.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use core::marker::PhantomData;
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU16, Ordering};
|
use atomic_polyfill::{AtomicU16, Ordering};
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -20,7 +20,7 @@ use crate::{pac, peripherals, Peripheral, RegExt};
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
mod buffered;
|
mod buffered;
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx};
|
pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum DataBits {
|
pub enum DataBits {
|
||||||
@ -203,11 +203,9 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub fn into_buffered(
|
pub fn into_buffered(
|
||||||
self,
|
self,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUartTx<'d, T> {
|
) -> BufferedUartTx<'d, T> {
|
||||||
into_ref!(irq);
|
|
||||||
|
|
||||||
buffered::init_buffers::<T>(irq, tx_buffer, &mut []);
|
buffered::init_buffers::<T>(irq, tx_buffer, &mut []);
|
||||||
|
|
||||||
BufferedUartTx { phantom: PhantomData }
|
BufferedUartTx { phantom: PhantomData }
|
||||||
@ -235,25 +233,24 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||||
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rx, irq, rx_dma);
|
into_ref!(rx, rx_dma);
|
||||||
Uart::<T, M>::init(None, Some(rx.map_into()), None, None, config);
|
Uart::<T, M>::init(None, Some(rx.map_into()), None, None, config);
|
||||||
Self::new_inner(Some(irq), Some(rx_dma.map_into()))
|
Self::new_inner(true, Some(rx_dma.map_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(irq: Option<PeripheralRef<'d, T::Interrupt>>, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
||||||
debug_assert_eq!(irq.is_some(), rx_dma.is_some());
|
debug_assert_eq!(has_irq, rx_dma.is_some());
|
||||||
if let Some(irq) = irq {
|
if has_irq {
|
||||||
unsafe {
|
unsafe {
|
||||||
// disable all error interrupts initially
|
// disable all error interrupts initially
|
||||||
T::regs().uartimsc().write(|w| w.0 = 0);
|
T::regs().uartimsc().write(|w| w.0 = 0);
|
||||||
|
T::Interrupt::steal().unpend();
|
||||||
|
T::Interrupt::steal().enable();
|
||||||
}
|
}
|
||||||
irq.set_handler(on_interrupt::<T>);
|
|
||||||
irq.unpend();
|
|
||||||
irq.enable();
|
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
rx_dma,
|
rx_dma,
|
||||||
@ -299,6 +296,12 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
|||||||
if let Some(_) = self.rx_dma {
|
if let Some(_) = self.rx_dma {
|
||||||
unsafe {
|
unsafe {
|
||||||
T::Interrupt::steal().disable();
|
T::Interrupt::steal().disable();
|
||||||
|
// clear dma flags. irq handlers use these to disambiguate among themselves.
|
||||||
|
T::regs().uartdmacr().write_clear(|reg| {
|
||||||
|
reg.set_rxdmae(true);
|
||||||
|
reg.set_txdmae(true);
|
||||||
|
reg.set_dmaonerr(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,33 +315,41 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rx);
|
into_ref!(rx);
|
||||||
Uart::<T, Blocking>::init(None, Some(rx.map_into()), None, None, config);
|
Uart::<T, Blocking>::init(None, Some(rx.map_into()), None, None, config);
|
||||||
Self::new_inner(None, None)
|
Self::new_inner(false, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub fn into_buffered(
|
pub fn into_buffered(
|
||||||
self,
|
self,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUartRx<'d, T> {
|
) -> BufferedUartRx<'d, T> {
|
||||||
into_ref!(irq);
|
|
||||||
|
|
||||||
buffered::init_buffers::<T>(irq, &mut [], rx_buffer);
|
buffered::init_buffers::<T>(irq, &mut [], rx_buffer);
|
||||||
|
|
||||||
BufferedUartRx { phantom: PhantomData }
|
BufferedUartRx { phantom: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
let uart = T::regs();
|
_uart: PhantomData<T>,
|
||||||
let state = T::dma_state();
|
}
|
||||||
let errs = uart.uartris().read();
|
|
||||||
state.rx_errs.store(errs.0 as u16, Ordering::Relaxed);
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
state.rx_err_waker.wake();
|
unsafe fn on_interrupt() {
|
||||||
// disable the error interrupts instead of clearing the flags. clearing the
|
let uart = T::regs();
|
||||||
// flags would allow the dma transfer to continue, potentially signaling
|
if !uart.uartdmacr().read().rxdmae() {
|
||||||
// completion before we can check for errors that happened *during* the transfer.
|
return;
|
||||||
uart.uartimsc().write_clear(|w| w.0 = errs.0);
|
}
|
||||||
|
|
||||||
|
let state = T::dma_state();
|
||||||
|
let errs = uart.uartris().read();
|
||||||
|
state.rx_errs.store(errs.0 as u16, Ordering::Relaxed);
|
||||||
|
state.rx_err_waker.wake();
|
||||||
|
// disable the error interrupts instead of clearing the flags. clearing the
|
||||||
|
// flags would allow the dma transfer to continue, potentially signaling
|
||||||
|
// completion before we can check for errors that happened *during* the transfer.
|
||||||
|
uart.uartimsc().write_clear(|w| w.0 = errs.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UartRx<'d, T, Async> {
|
impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||||
@ -428,7 +439,17 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
|||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(tx, rx);
|
into_ref!(tx, rx);
|
||||||
Self::new_inner(uart, tx.map_into(), rx.map_into(), None, None, None, None, None, config)
|
Self::new_inner(
|
||||||
|
uart,
|
||||||
|
tx.map_into(),
|
||||||
|
rx.map_into(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
config,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new UART with hardware flow control (RTS/CTS)
|
/// Create a new UART with hardware flow control (RTS/CTS)
|
||||||
@ -447,7 +468,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
|||||||
rx.map_into(),
|
rx.map_into(),
|
||||||
Some(rts.map_into()),
|
Some(rts.map_into()),
|
||||||
Some(cts.map_into()),
|
Some(cts.map_into()),
|
||||||
None,
|
false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
config,
|
config,
|
||||||
@ -457,12 +478,10 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub fn into_buffered(
|
pub fn into_buffered(
|
||||||
self,
|
self,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUart<'d, T> {
|
) -> BufferedUart<'d, T> {
|
||||||
into_ref!(irq);
|
|
||||||
|
|
||||||
buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer);
|
buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer);
|
||||||
|
|
||||||
BufferedUart {
|
BufferedUart {
|
||||||
@ -478,19 +497,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
|||||||
uart: impl Peripheral<P = T> + 'd,
|
uart: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||||
tx_dma: impl Peripheral<P = impl Channel> + 'd,
|
tx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(tx, rx, irq, tx_dma, rx_dma);
|
into_ref!(tx, rx, tx_dma, rx_dma);
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
uart,
|
uart,
|
||||||
tx.map_into(),
|
tx.map_into(),
|
||||||
rx.map_into(),
|
rx.map_into(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(irq),
|
true,
|
||||||
Some(tx_dma.map_into()),
|
Some(tx_dma.map_into()),
|
||||||
Some(rx_dma.map_into()),
|
Some(rx_dma.map_into()),
|
||||||
config,
|
config,
|
||||||
@ -504,19 +523,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
|||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||||
tx_dma: impl Peripheral<P = impl Channel> + 'd,
|
tx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
rx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(tx, rx, cts, rts, irq, tx_dma, rx_dma);
|
into_ref!(tx, rx, cts, rts, tx_dma, rx_dma);
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
uart,
|
uart,
|
||||||
tx.map_into(),
|
tx.map_into(),
|
||||||
rx.map_into(),
|
rx.map_into(),
|
||||||
Some(rts.map_into()),
|
Some(rts.map_into()),
|
||||||
Some(cts.map_into()),
|
Some(cts.map_into()),
|
||||||
Some(irq),
|
true,
|
||||||
Some(tx_dma.map_into()),
|
Some(tx_dma.map_into()),
|
||||||
Some(rx_dma.map_into()),
|
Some(rx_dma.map_into()),
|
||||||
config,
|
config,
|
||||||
@ -531,7 +550,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
mut rx: PeripheralRef<'d, AnyPin>,
|
mut rx: PeripheralRef<'d, AnyPin>,
|
||||||
mut rts: Option<PeripheralRef<'d, AnyPin>>,
|
mut rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
mut cts: Option<PeripheralRef<'d, AnyPin>>,
|
mut cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
irq: Option<PeripheralRef<'d, T::Interrupt>>,
|
has_irq: bool,
|
||||||
tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||||
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -546,7 +565,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
tx: UartTx::new_inner(tx_dma),
|
tx: UartTx::new_inner(tx_dma),
|
||||||
rx: UartRx::new_inner(irq, rx_dma),
|
rx: UartRx::new_inner(has_irq, rx_dma),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use core::slice;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_common::into_ref;
|
use embassy_cortex_m::interrupt::{self, Binding};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_usb_driver as driver;
|
use embassy_usb_driver as driver;
|
||||||
use embassy_usb_driver::{
|
use embassy_usb_driver::{
|
||||||
@ -105,11 +105,11 @@ pub struct Driver<'d, T: Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Driver<'d, T> {
|
impl<'d, T: Instance> Driver<'d, T> {
|
||||||
pub fn new(_usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
|
pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
|
||||||
into_ref!(irq);
|
unsafe {
|
||||||
irq.set_handler(Self::on_interrupt);
|
T::Interrupt::steal().unpend();
|
||||||
irq.unpend();
|
T::Interrupt::steal().enable();
|
||||||
irq.enable();
|
}
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -149,47 +149,6 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
|
||||||
unsafe {
|
|
||||||
let regs = T::regs();
|
|
||||||
//let x = regs.istr().read().0;
|
|
||||||
//trace!("USB IRQ: {:08x}", x);
|
|
||||||
|
|
||||||
let ints = regs.ints().read();
|
|
||||||
|
|
||||||
if ints.bus_reset() {
|
|
||||||
regs.inte().write_clear(|w| w.set_bus_reset(true));
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
}
|
|
||||||
if ints.dev_resume_from_host() {
|
|
||||||
regs.inte().write_clear(|w| w.set_dev_resume_from_host(true));
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
}
|
|
||||||
if ints.dev_suspend() {
|
|
||||||
regs.inte().write_clear(|w| w.set_dev_suspend(true));
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
}
|
|
||||||
if ints.setup_req() {
|
|
||||||
regs.inte().write_clear(|w| w.set_setup_req(true));
|
|
||||||
EP_OUT_WAKERS[0].wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ints.buff_status() {
|
|
||||||
let s = regs.buff_status().read();
|
|
||||||
regs.buff_status().write_value(s);
|
|
||||||
|
|
||||||
for i in 0..EP_COUNT {
|
|
||||||
if s.ep_in(i) {
|
|
||||||
EP_IN_WAKERS[i].wake();
|
|
||||||
}
|
|
||||||
if s.ep_out(i) {
|
|
||||||
EP_OUT_WAKERS[i].wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_endpoint<D: Dir>(
|
fn alloc_endpoint<D: Dir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
@ -288,6 +247,51 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_uart: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = T::regs();
|
||||||
|
//let x = regs.istr().read().0;
|
||||||
|
//trace!("USB IRQ: {:08x}", x);
|
||||||
|
|
||||||
|
let ints = regs.ints().read();
|
||||||
|
|
||||||
|
if ints.bus_reset() {
|
||||||
|
regs.inte().write_clear(|w| w.set_bus_reset(true));
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
if ints.dev_resume_from_host() {
|
||||||
|
regs.inte().write_clear(|w| w.set_dev_resume_from_host(true));
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
if ints.dev_suspend() {
|
||||||
|
regs.inte().write_clear(|w| w.set_dev_suspend(true));
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
if ints.setup_req() {
|
||||||
|
regs.inte().write_clear(|w| w.set_setup_req(true));
|
||||||
|
EP_OUT_WAKERS[0].wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ints.buff_status() {
|
||||||
|
let s = regs.buff_status().read();
|
||||||
|
regs.buff_status().write_value(s);
|
||||||
|
|
||||||
|
for i in 0..EP_COUNT {
|
||||||
|
if s.ep_in(i) {
|
||||||
|
EP_IN_WAKERS[i].wake();
|
||||||
|
}
|
||||||
|
if s.ep_out(i) {
|
||||||
|
EP_OUT_WAKERS[i].wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
||||||
type EndpointOut = Endpoint<'d, T, Out>;
|
type EndpointOut = Endpoint<'d, T, Out>;
|
||||||
type EndpointIn = Endpoint<'d, T, In>;
|
type EndpointIn = Endpoint<'d, T, In>;
|
||||||
|
@ -4,16 +4,19 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::adc::{Adc, Config};
|
use embassy_rp::adc::{Adc, Config, InterruptHandler};
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
ADC_IRQ_FIFO => InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
let irq = interrupt::take!(ADC_IRQ_FIFO);
|
let mut adc = Adc::new(p.ADC, Irqs, Config::default());
|
||||||
let mut adc = Adc::new(p.ADC, irq, Config::default());
|
|
||||||
|
|
||||||
let mut p26 = p.PIN_26;
|
let mut p26 = p.PIN_26;
|
||||||
let mut p27 = p.PIN_27;
|
let mut p27 = p.PIN_27;
|
||||||
|
@ -4,12 +4,17 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::i2c::{self, Config};
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::i2c::{self, Config, InterruptHandler};
|
||||||
|
use embassy_rp::peripherals::I2C1;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_hal_async::i2c::I2c;
|
use embedded_hal_async::i2c::I2c;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
I2C1_IRQ => InterruptHandler<I2C1>;
|
||||||
|
});
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod mcp23017 {
|
mod mcp23017 {
|
||||||
pub const ADDR: u8 = 0x20; // default addr
|
pub const ADDR: u8 = 0x20; // default addr
|
||||||
@ -64,10 +69,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let sda = p.PIN_14;
|
let sda = p.PIN_14;
|
||||||
let scl = p.PIN_15;
|
let scl = p.PIN_15;
|
||||||
let irq = interrupt::take!(I2C1_IRQ);
|
|
||||||
|
|
||||||
info!("set up i2c ");
|
info!("set up i2c ");
|
||||||
let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, irq, Config::default());
|
let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default());
|
||||||
|
|
||||||
use mcp23017::*;
|
use mcp23017::*;
|
||||||
|
|
||||||
|
@ -5,13 +5,17 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_executor::_export::StaticCell;
|
use embassy_executor::_export::StaticCell;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::peripherals::UART0;
|
use embassy_rp::peripherals::UART0;
|
||||||
use embassy_rp::uart::{BufferedUart, BufferedUartRx, Config};
|
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_io::asynch::{Read, Write};
|
use embedded_io::asynch::{Read, Write};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UART0_IRQ => BufferedInterruptHandler<UART0>;
|
||||||
|
});
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
($val:expr) => {{
|
($val:expr) => {{
|
||||||
type T = impl Sized;
|
type T = impl Sized;
|
||||||
@ -26,10 +30,9 @@ async fn main(spawner: Spawner) {
|
|||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
|
|
||||||
let irq = interrupt::take!(UART0_IRQ);
|
|
||||||
let tx_buf = &mut singleton!([0u8; 16])[..];
|
let tx_buf = &mut singleton!([0u8; 16])[..];
|
||||||
let rx_buf = &mut singleton!([0u8; 16])[..];
|
let rx_buf = &mut singleton!([0u8; 16])[..];
|
||||||
let uart = BufferedUart::new(uart, irq, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
|
let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
|
||||||
let (rx, mut tx) = uart.split();
|
let (rx, mut tx) = uart.split();
|
||||||
|
|
||||||
unwrap!(spawner.spawn(reader(rx)));
|
unwrap!(spawner.spawn(reader(rx)));
|
||||||
|
@ -7,24 +7,22 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::peripherals::UART1;
|
use embassy_rp::peripherals::UART1;
|
||||||
use embassy_rp::uart::{Async, Config, UartRx, UartTx};
|
use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UART1_IRQ => InterruptHandler<UART1>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
|
let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
|
||||||
let uart_rx = UartRx::new(
|
let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
|
||||||
p.UART1,
|
|
||||||
p.PIN_5,
|
|
||||||
interrupt::take!(UART1_IRQ),
|
|
||||||
p.DMA_CH1,
|
|
||||||
Config::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
unwrap!(spawner.spawn(reader(uart_rx)));
|
unwrap!(spawner.spawn(reader(uart_rx)));
|
||||||
|
|
||||||
|
@ -6,8 +6,9 @@ use defmt::*;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Stack, StackResources};
|
use embassy_net::{Stack, StackResources};
|
||||||
use embassy_rp::usb::Driver;
|
use embassy_rp::peripherals::USB;
|
||||||
use embassy_rp::{interrupt, peripherals};
|
use embassy_rp::usb::{Driver, InterruptHandler};
|
||||||
|
use embassy_rp::{bind_interrupts, peripherals};
|
||||||
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
||||||
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
@ -15,6 +16,10 @@ use embedded_io::asynch::Write;
|
|||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBCTRL_IRQ => InterruptHandler<USB>;
|
||||||
|
});
|
||||||
|
|
||||||
type MyDriver = Driver<'static, peripherals::USB>;
|
type MyDriver = Driver<'static, peripherals::USB>;
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
@ -48,8 +53,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBCTRL_IRQ);
|
let driver = Driver::new(p.USB, Irqs);
|
||||||
let driver = Driver::new(p.USB, irq);
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::peripherals::USB;
|
use embassy_rp::peripherals::USB;
|
||||||
use embassy_rp::usb::Driver;
|
use embassy_rp::usb::{Driver, InterruptHandler};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBCTRL_IRQ => InterruptHandler<USB>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn logger_task(driver: Driver<'static, USB>) {
|
async fn logger_task(driver: Driver<'static, USB>) {
|
||||||
embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
|
embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
|
||||||
@ -17,8 +21,7 @@ async fn logger_task(driver: Driver<'static, USB>) {
|
|||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
let irq = interrupt::take!(USBCTRL_IRQ);
|
let driver = Driver::new(p.USB, Irqs);
|
||||||
let driver = Driver::new(p.USB, irq);
|
|
||||||
spawner.spawn(logger_task(driver)).unwrap();
|
spawner.spawn(logger_task(driver)).unwrap();
|
||||||
|
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
|
@ -5,13 +5,18 @@
|
|||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::usb::{Driver, Instance};
|
use embassy_rp::peripherals::USB;
|
||||||
|
use embassy_rp::usb::{Driver, Instance, InterruptHandler};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBCTRL_IRQ => InterruptHandler<USB>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
info!("Hello there!");
|
info!("Hello there!");
|
||||||
@ -19,8 +24,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBCTRL_IRQ);
|
let driver = Driver::new(p.USB, Irqs);
|
||||||
let driver = Driver::new(p.USB, irq);
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
|
@ -4,13 +4,18 @@
|
|||||||
|
|
||||||
use defmt::{assert_eq, panic, *};
|
use defmt::{assert_eq, panic, *};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Level, Output};
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::peripherals::UART0;
|
||||||
use embassy_rp::uart::{BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
|
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_io::asynch::{Read, ReadExactError, Write};
|
use embedded_io::asynch::{Read, ReadExactError, Write};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UART0_IRQ => BufferedInterruptHandler<UART0>;
|
||||||
|
});
|
||||||
|
|
||||||
async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> {
|
async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> {
|
||||||
let mut buf = [255; N];
|
let mut buf = [255; N];
|
||||||
match uart.read_exact(&mut buf).await {
|
match uart.read_exact(&mut buf).await {
|
||||||
@ -60,13 +65,12 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
let mut irq = interrupt::take!(UART0_IRQ);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let tx_buf = &mut [0u8; 16];
|
let tx_buf = &mut [0u8; 16];
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
||||||
|
|
||||||
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
||||||
// bufferedUart.
|
// bufferedUart.
|
||||||
@ -86,7 +90,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let tx_buf = &mut [0u8; 16];
|
let tx_buf = &mut [0u8; 16];
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
||||||
|
|
||||||
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
||||||
// bufferedUart.
|
// bufferedUart.
|
||||||
@ -121,7 +125,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.baudrate = 1000;
|
config.baudrate = 1000;
|
||||||
let tx_buf = &mut [0u8; 16];
|
let tx_buf = &mut [0u8; 16];
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config);
|
||||||
|
|
||||||
// break on empty buffer
|
// break on empty buffer
|
||||||
uart.send_break(20).await;
|
uart.send_break(20).await;
|
||||||
@ -155,7 +159,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.baudrate = 1000;
|
config.baudrate = 1000;
|
||||||
config.parity = Parity::ParityEven;
|
config.parity = Parity::ParityEven;
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
let mut uart = BufferedUartRx::new(&mut uart, &mut irq, &mut rx, rx_buf, config);
|
let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config);
|
||||||
|
|
||||||
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) {
|
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) {
|
||||||
send(pin, v, Some(parity != 0)).await;
|
send(pin, v, Some(parity != 0)).await;
|
||||||
@ -202,7 +206,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.baudrate = 1000;
|
config.baudrate = 1000;
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
let mut uart = BufferedUartRx::new(&mut uart, &mut irq, &mut rx, rx_buf, config);
|
let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config);
|
||||||
|
|
||||||
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) {
|
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) {
|
||||||
if good {
|
if good {
|
||||||
|
@ -4,12 +4,17 @@
|
|||||||
|
|
||||||
use defmt::{assert_eq, *};
|
use defmt::{assert_eq, *};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Level, Output};
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::peripherals::UART0;
|
||||||
use embassy_rp::uart::{Async, Config, Error, Instance, Parity, Uart, UartRx};
|
use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UART0_IRQ => InterruptHandler<UART0>;
|
||||||
|
});
|
||||||
|
|
||||||
async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
|
async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
|
||||||
let mut buf = [255; N];
|
let mut buf = [255; N];
|
||||||
uart.read(&mut buf).await?;
|
uart.read(&mut buf).await?;
|
||||||
@ -51,7 +56,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
let mut irq = interrupt::take!(UART0_IRQ);
|
|
||||||
|
|
||||||
// We can't send too many bytes, they have to fit in the FIFO.
|
// We can't send too many bytes, they have to fit in the FIFO.
|
||||||
// This is because we aren't sending+receiving at the same time.
|
// This is because we aren't sending+receiving at the same time.
|
||||||
@ -61,7 +65,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut uart,
|
&mut uart,
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&mut rx,
|
&mut rx,
|
||||||
&mut irq,
|
Irqs,
|
||||||
&mut p.DMA_CH0,
|
&mut p.DMA_CH0,
|
||||||
&mut p.DMA_CH1,
|
&mut p.DMA_CH1,
|
||||||
config,
|
config,
|
||||||
@ -82,7 +86,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut uart,
|
&mut uart,
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&mut rx,
|
&mut rx,
|
||||||
&mut irq,
|
Irqs,
|
||||||
&mut p.DMA_CH0,
|
&mut p.DMA_CH0,
|
||||||
&mut p.DMA_CH1,
|
&mut p.DMA_CH1,
|
||||||
config,
|
config,
|
||||||
@ -111,7 +115,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut uart,
|
&mut uart,
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&mut rx,
|
&mut rx,
|
||||||
&mut irq,
|
Irqs,
|
||||||
&mut p.DMA_CH0,
|
&mut p.DMA_CH0,
|
||||||
&mut p.DMA_CH1,
|
&mut p.DMA_CH1,
|
||||||
config,
|
config,
|
||||||
@ -154,7 +158,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.baudrate = 1000;
|
config.baudrate = 1000;
|
||||||
config.parity = Parity::ParityEven;
|
config.parity = Parity::ParityEven;
|
||||||
let mut uart = UartRx::new(&mut uart, &mut rx, &mut irq, &mut p.DMA_CH0, config);
|
let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config);
|
||||||
|
|
||||||
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) {
|
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) {
|
||||||
send(pin, v, Some(parity != 0)).await;
|
send(pin, v, Some(parity != 0)).await;
|
||||||
@ -199,7 +203,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
// choose a very slow baud rate to make tests reliable even with O0
|
// choose a very slow baud rate to make tests reliable even with O0
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.baudrate = 1000;
|
config.baudrate = 1000;
|
||||||
let mut uart = UartRx::new(&mut uart, &mut rx, &mut irq, &mut p.DMA_CH0, config);
|
let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config);
|
||||||
|
|
||||||
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) {
|
async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) {
|
||||||
if good {
|
if good {
|
||||||
|
@ -4,11 +4,16 @@
|
|||||||
|
|
||||||
use defmt::{assert_eq, *};
|
use defmt::{assert_eq, *};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::uart::{Config, Uart};
|
use embassy_rp::peripherals::UART0;
|
||||||
|
use embassy_rp::uart::{BufferedInterruptHandler, Config, Uart};
|
||||||
use embedded_io::asynch::{Read, Write};
|
use embedded_io::asynch::{Read, Write};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UART0_IRQ => BufferedInterruptHandler<UART0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
@ -29,11 +34,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
uart.blocking_read(&mut buf).unwrap();
|
uart.blocking_read(&mut buf).unwrap();
|
||||||
assert_eq!(buf, data);
|
assert_eq!(buf, data);
|
||||||
|
|
||||||
let irq = interrupt::take!(UART0_IRQ);
|
|
||||||
let tx_buf = &mut [0u8; 16];
|
let tx_buf = &mut [0u8; 16];
|
||||||
let rx_buf = &mut [0u8; 16];
|
let rx_buf = &mut [0u8; 16];
|
||||||
|
|
||||||
let mut uart = uart.into_buffered(irq, tx_buf, rx_buf);
|
let mut uart = uart.into_buffered(Irqs, tx_buf, rx_buf);
|
||||||
|
|
||||||
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
||||||
// bufferedUart.
|
// bufferedUart.
|
||||||
|
Loading…
Reference in New Issue
Block a user