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:
bors[bot] 2023-05-15 15:59:30 +00:00 committed by GitHub
commit 1a87f7477a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 374 additions and 277 deletions

View File

@ -3,12 +3,12 @@ use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_hal_common::into_ref;
use embassy_cortex_m::interrupt::{Binding, Interrupt};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal_02::adc::{Channel, OneShot};
use crate::gpio::Pin;
use crate::interrupt::{self, InterruptExt};
use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO};
use crate::peripherals::ADC;
use crate::{pac, peripherals, Peripheral};
static WAKER: AtomicWaker = AtomicWaker::new();
@ -47,10 +47,9 @@ impl<'d> Adc<'d> {
pub fn new(
_inner: impl Peripheral<P = ADC> + 'd,
irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd,
_irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>,
_config: Config,
) -> Self {
into_ref!(irq);
unsafe {
let reset = Self::reset();
crate::reset::reset(reset);
@ -63,14 +62,10 @@ impl<'d> Adc<'d> {
}
// Setup IRQ
irq.disable();
irq.set_handler(|_| unsafe {
let r = Self::regs();
r.inte().write(|w| w.set_fifo(false));
WAKER.wake();
});
irq.unpend();
irq.enable();
unsafe {
ADC_IRQ_FIFO::steal().unpend();
ADC_IRQ_FIFO::steal().enable();
};
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_27, 1);
impl_pin!(PIN_28, 2);

View File

@ -2,7 +2,7 @@ use core::future;
use core::marker::PhantomData;
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_sync::waitqueue::AtomicWaker;
use pac::i2c;
@ -75,23 +75,21 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<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,
) -> Self {
into_ref!(scl, sda, irq);
into_ref!(scl, sda);
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
irq.set_handler(Self::on_interrupt);
unsafe {
let i2c = T::regs();
// mask everything initially
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
}
@ -115,14 +113,6 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
.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> {
if buffer.is_empty() {
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> {
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,

View File

@ -1,11 +1,7 @@
//! Interrupt management
//!
//! This module implements an API for managing interrupts compatible with
//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time.
// Re-exports
//! Interrupt definitions and macros to bind them.
pub use cortex_m::interrupt::{CriticalSection, Mutex};
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;
declare!(TIMER_IRQ_0);
@ -40,3 +36,30 @@ declare!(SWI_IRQ_2);
declare!(SWI_IRQ_3);
declare!(SWI_IRQ_4);
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 {}
)*
)*
};
}

View File

@ -3,7 +3,7 @@ use core::slice;
use core::task::Poll;
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_sync::waitqueue::AtomicWaker;
use embassy_time::{Duration, Timer};
@ -52,7 +52,7 @@ pub struct BufferedUartTx<'d, T: Instance> {
}
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],
rx_buffer: &'d mut [u8],
) {
@ -79,24 +79,23 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
w.set_rtim(true);
w.set_txim(true);
});
};
irq.set_handler(on_interrupt::<T>);
irq.unpend();
irq.enable();
T::Interrupt::steal().unpend();
T::Interrupt::steal().enable();
};
}
impl<'d, T: Instance> BufferedUart<'d, T> {
pub fn new(
_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,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> 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);
init_buffers::<T>(irq, tx_buffer, rx_buffer);
@ -109,7 +108,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
pub fn new_with_rtscts(
_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,
rx: impl Peripheral<P = impl RxPin<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],
config: Config,
) -> Self {
into_ref!(irq, tx, rx, cts, rts);
into_ref!(tx, rx, cts, rts);
super::Uart::<'d, T, Async>::init(
Some(tx.map_into()),
@ -163,12 +162,12 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
impl<'d, T: Instance> BufferedUartRx<'d, T> {
pub fn new(
_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_buffer: &'d mut [u8],
config: Config,
) -> Self {
into_ref!(irq, rx);
into_ref!(rx);
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
init_buffers::<T>(irq, &mut [], rx_buffer);
@ -178,13 +177,13 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
pub fn new_with_rts(
_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,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_buffer: &'d mut [u8],
config: Config,
) -> 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);
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> {
pub fn new(
_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_buffer: &'d mut [u8],
config: Config,
) -> Self {
into_ref!(irq, tx);
into_ref!(tx);
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
init_buffers::<T>(irq, tx_buffer, &mut []);
@ -327,13 +326,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
pub fn new_with_cts(
_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,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_buffer: &'d mut [u8],
config: Config,
) -> 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);
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 ()) {
let r = T::regs();
let s = T::buffered_state();
pub struct BufferedInterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
unsafe {
// Clear TX and error interrupt flags
// RX interrupt flags are cleared by reading from the FIFO.
let ris = r.uartris().read();
r.uarticr().write(|w| {
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");
impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
if r.uartdmacr().read().rxdmae() {
return;
}
// 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);
let s = T::buffered_state();
unsafe {
// Clear TX and error interrupt flags
// RX interrupt flags are cleared by reading from the FIFO.
let ris = r.uartris().read();
r.uarticr().write(|w| {
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());
});
}
// 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;
trace!("on_interrupt ris={:#X}", ris.0);
// Errors
if ris.feris() {
warn!("Framing error");
}
r.uartdr().write(|w| w.set_data(*tx_byte));
n_written += 1;
if ris.peris() {
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.
}
}

View File

@ -3,7 +3,7 @@ use core::marker::PhantomData;
use core::task::Poll;
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_hal_common::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
@ -20,7 +20,7 @@ use crate::{pac, peripherals, Peripheral, RegExt};
#[cfg(feature = "nightly")]
mod buffered;
#[cfg(feature = "nightly")]
pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx};
pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum DataBits {
@ -203,11 +203,9 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
#[cfg(feature = "nightly")]
pub fn into_buffered(
self,
irq: impl Peripheral<P = T::Interrupt> + 'd,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
) -> BufferedUartTx<'d, T> {
into_ref!(irq);
buffered::init_buffers::<T>(irq, tx_buffer, &mut []);
BufferedUartTx { phantom: PhantomData }
@ -235,25 +233,24 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
pub fn new(
_uart: impl Peripheral<P = 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,
config: Config,
) -> Self {
into_ref!(rx, irq, rx_dma);
into_ref!(rx, rx_dma);
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 {
debug_assert_eq!(irq.is_some(), rx_dma.is_some());
if let Some(irq) = irq {
fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
debug_assert_eq!(has_irq, rx_dma.is_some());
if has_irq {
unsafe {
// disable all error interrupts initially
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 {
rx_dma,
@ -299,6 +296,12 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
if let Some(_) = self.rx_dma {
unsafe {
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 {
into_ref!(rx);
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")]
pub fn into_buffered(
self,
irq: impl Peripheral<P = T::Interrupt> + 'd,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
rx_buffer: &'d mut [u8],
) -> BufferedUartRx<'d, T> {
into_ref!(irq);
buffered::init_buffers::<T>(irq, &mut [], rx_buffer);
BufferedUartRx { phantom: PhantomData }
}
}
unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
let uart = T::regs();
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);
pub struct InterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let uart = T::regs();
if !uart.uartdmacr().read().rxdmae() {
return;
}
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> {
@ -428,7 +439,17 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
config: Config,
) -> Self {
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)
@ -447,7 +468,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
rx.map_into(),
Some(rts.map_into()),
Some(cts.map_into()),
None,
false,
None,
None,
config,
@ -457,12 +478,10 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
#[cfg(feature = "nightly")]
pub fn into_buffered(
self,
irq: impl Peripheral<P = T::Interrupt> + 'd,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
) -> BufferedUart<'d, T> {
into_ref!(irq);
buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer);
BufferedUart {
@ -478,19 +497,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
uart: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<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,
rx_dma: impl Peripheral<P = impl Channel> + 'd,
config: Config,
) -> Self {
into_ref!(tx, rx, irq, tx_dma, rx_dma);
into_ref!(tx, rx, tx_dma, rx_dma);
Self::new_inner(
uart,
tx.map_into(),
rx.map_into(),
None,
None,
Some(irq),
true,
Some(tx_dma.map_into()),
Some(rx_dma.map_into()),
config,
@ -504,19 +523,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<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,
rx_dma: impl Peripheral<P = impl Channel> + 'd,
config: Config,
) -> 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(
uart,
tx.map_into(),
rx.map_into(),
Some(rts.map_into()),
Some(cts.map_into()),
Some(irq),
true,
Some(tx_dma.map_into()),
Some(rx_dma.map_into()),
config,
@ -531,7 +550,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
mut rx: PeripheralRef<'d, AnyPin>,
mut rts: 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>>,
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
config: Config,
@ -546,7 +565,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
Self {
tx: UartTx::new_inner(tx_dma),
rx: UartRx::new_inner(irq, rx_dma),
rx: UartRx::new_inner(has_irq, rx_dma),
}
}

View File

@ -4,7 +4,7 @@ use core::slice;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_hal_common::into_ref;
use embassy_cortex_m::interrupt::{self, Binding};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver as driver;
use embassy_usb_driver::{
@ -105,11 +105,11 @@ pub struct Driver<'d, T: Instance> {
}
impl<'d, T: Instance> Driver<'d, T> {
pub fn new(_usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
into_ref!(irq);
irq.set_handler(Self::on_interrupt);
irq.unpend();
irq.enable();
pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
unsafe {
T::Interrupt::steal().unpend();
T::Interrupt::steal().enable();
}
let regs = T::regs();
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>(
&mut self,
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> {
type EndpointOut = Endpoint<'d, T, Out>;
type EndpointIn = Endpoint<'d, T, In>;

View File

@ -4,16 +4,19 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::adc::{Adc, Config};
use embassy_rp::interrupt;
use embassy_rp::adc::{Adc, Config, InterruptHandler};
use embassy_rp::bind_interrupts;
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
ADC_IRQ_FIFO => InterruptHandler;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let irq = interrupt::take!(ADC_IRQ_FIFO);
let mut adc = Adc::new(p.ADC, irq, Config::default());
let mut adc = Adc::new(p.ADC, Irqs, Config::default());
let mut p26 = p.PIN_26;
let mut p27 = p.PIN_27;

View File

@ -4,12 +4,17 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::i2c::{self, Config};
use embassy_rp::interrupt;
use embassy_rp::bind_interrupts;
use embassy_rp::i2c::{self, Config, InterruptHandler};
use embassy_rp::peripherals::I2C1;
use embassy_time::{Duration, Timer};
use embedded_hal_async::i2c::I2c;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
I2C1_IRQ => InterruptHandler<I2C1>;
});
#[allow(dead_code)]
mod mcp23017 {
pub const ADDR: u8 = 0x20; // default addr
@ -64,10 +69,9 @@ async fn main(_spawner: Spawner) {
let sda = p.PIN_14;
let scl = p.PIN_15;
let irq = interrupt::take!(I2C1_IRQ);
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::*;

View File

@ -5,13 +5,17 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_executor::_export::StaticCell;
use embassy_rp::interrupt;
use embassy_rp::bind_interrupts;
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 embedded_io::asynch::{Read, Write};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
UART0_IRQ => BufferedInterruptHandler<UART0>;
});
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
@ -26,10 +30,9 @@ async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
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 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();
unwrap!(spawner.spawn(reader(rx)));

View File

@ -7,24 +7,22 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::interrupt;
use embassy_rp::bind_interrupts;
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 {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
UART1_IRQ => InterruptHandler<UART1>;
});
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
let uart_rx = UartRx::new(
p.UART1,
p.PIN_5,
interrupt::take!(UART1_IRQ),
p.DMA_CH1,
Config::default(),
);
let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
unwrap!(spawner.spawn(reader(uart_rx)));

View File

@ -6,8 +6,9 @@ use defmt::*;
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{Stack, StackResources};
use embassy_rp::usb::Driver;
use embassy_rp::{interrupt, peripherals};
use embassy_rp::peripherals::USB;
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::{CdcNcmClass, State};
use embassy_usb::{Builder, Config, UsbDevice};
@ -15,6 +16,10 @@ use embedded_io::asynch::Write;
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => InterruptHandler<USB>;
});
type MyDriver = Driver<'static, peripherals::USB>;
macro_rules! singleton {
@ -48,8 +53,7 @@ async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
// Create the driver, from the HAL.
let irq = interrupt::take!(USBCTRL_IRQ);
let driver = Driver::new(p.USB, irq);
let driver = Driver::new(p.USB, Irqs);
// Create embassy-usb Config
let mut config = Config::new(0xc0de, 0xcafe);

View File

@ -3,12 +3,16 @@
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
use embassy_rp::interrupt;
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals::USB;
use embassy_rp::usb::Driver;
use embassy_rp::usb::{Driver, InterruptHandler};
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => InterruptHandler<USB>;
});
#[embassy_executor::task]
async fn logger_task(driver: Driver<'static, USB>) {
embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
@ -17,8 +21,7 @@ async fn logger_task(driver: Driver<'static, USB>) {
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let irq = interrupt::take!(USBCTRL_IRQ);
let driver = Driver::new(p.USB, irq);
let driver = Driver::new(p.USB, Irqs);
spawner.spawn(logger_task(driver)).unwrap();
let mut counter = 0;

View File

@ -5,13 +5,18 @@
use defmt::{info, panic};
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_rp::interrupt;
use embassy_rp::usb::{Driver, Instance};
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals::USB;
use embassy_rp::usb::{Driver, Instance, InterruptHandler};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::driver::EndpointError;
use embassy_usb::{Builder, Config};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => InterruptHandler<USB>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
info!("Hello there!");
@ -19,8 +24,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
// Create the driver, from the HAL.
let irq = interrupt::take!(USBCTRL_IRQ);
let driver = Driver::new(p.USB, irq);
let driver = Driver::new(p.USB, Irqs);
// Create embassy-usb Config
let mut config = Config::new(0xc0de, 0xcafe);

View File

@ -4,13 +4,18 @@
use defmt::{assert_eq, panic, *};
use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::interrupt;
use embassy_rp::uart::{BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
use embassy_time::{Duration, Timer};
use embedded_io::asynch::{Read, ReadExactError, Write};
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> {
let mut buf = [255; N];
match uart.read_exact(&mut buf).await {
@ -60,13 +65,12 @@ async fn main(_spawner: Spawner) {
info!("Hello World!");
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 tx_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
// bufferedUart.
@ -86,7 +90,7 @@ async fn main(_spawner: Spawner) {
let config = Config::default();
let tx_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
// bufferedUart.
@ -121,7 +125,7 @@ async fn main(_spawner: Spawner) {
config.baudrate = 1000;
let tx_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
uart.send_break(20).await;
@ -155,7 +159,7 @@ async fn main(_spawner: Spawner) {
config.baudrate = 1000;
config.parity = Parity::ParityEven;
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) {
send(pin, v, Some(parity != 0)).await;
@ -202,7 +206,7 @@ async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.baudrate = 1000;
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) {
if good {

View File

@ -4,12 +4,17 @@
use defmt::{assert_eq, *};
use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::interrupt;
use embassy_rp::uart::{Async, Config, Error, Instance, Parity, Uart, UartRx};
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx};
use embassy_time::{Duration, Timer};
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> {
let mut buf = [255; N];
uart.read(&mut buf).await?;
@ -51,7 +56,6 @@ async fn main(_spawner: Spawner) {
info!("Hello World!");
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.
// This is because we aren't sending+receiving at the same time.
@ -61,7 +65,7 @@ async fn main(_spawner: Spawner) {
&mut uart,
&mut tx,
&mut rx,
&mut irq,
Irqs,
&mut p.DMA_CH0,
&mut p.DMA_CH1,
config,
@ -82,7 +86,7 @@ async fn main(_spawner: Spawner) {
&mut uart,
&mut tx,
&mut rx,
&mut irq,
Irqs,
&mut p.DMA_CH0,
&mut p.DMA_CH1,
config,
@ -111,7 +115,7 @@ async fn main(_spawner: Spawner) {
&mut uart,
&mut tx,
&mut rx,
&mut irq,
Irqs,
&mut p.DMA_CH0,
&mut p.DMA_CH1,
config,
@ -154,7 +158,7 @@ async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.baudrate = 1000;
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) {
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
let mut config = Config::default();
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) {
if good {

View File

@ -4,11 +4,16 @@
use defmt::{assert_eq, *};
use embassy_executor::Spawner;
use embassy_rp::interrupt;
use embassy_rp::uart::{Config, Uart};
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{BufferedInterruptHandler, Config, Uart};
use embedded_io::asynch::{Read, Write};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
UART0_IRQ => BufferedInterruptHandler<UART0>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
@ -29,11 +34,10 @@ async fn main(_spawner: Spawner) {
uart.blocking_read(&mut buf).unwrap();
assert_eq!(buf, data);
let irq = interrupt::take!(UART0_IRQ);
let tx_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
// bufferedUart.