diff options
| -rw-r--r-- | embassy-cortex-m/src/interrupt.rs | 30 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 33 |
2 files changed, 59 insertions, 4 deletions
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index ead9d52fe..3a82726df 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs | |||
| @@ -13,6 +13,36 @@ pub mod _export { | |||
| 13 | pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; | 13 | pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | /// Interrupt handler trait. | ||
| 17 | /// | ||
| 18 | /// Drivers that need to handle interrupts implement this trait. | ||
| 19 | /// The user must ensure `on_interrupt()` is called every time the interrupt fires. | ||
| 20 | /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. | ||
| 21 | pub trait Handler<I: Interrupt> { | ||
| 22 | /// Interrupt handler function. | ||
| 23 | /// | ||
| 24 | /// Must be called every time the `I` interrupt fires, synchronously from | ||
| 25 | /// the interrupt handler context. | ||
| 26 | /// | ||
| 27 | /// # Safety | ||
| 28 | /// | ||
| 29 | /// This function must ONLY be called from the interrupt handler for `I`. | ||
| 30 | unsafe fn on_interrupt(); | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Compile-time assertion that an interrupt has been bound to a handler. | ||
| 34 | /// | ||
| 35 | /// For the vast majority of cases, you should use the `bind_interrupts!` | ||
| 36 | /// macro instead of writing `unsafe impl`s of this trait. | ||
| 37 | /// | ||
| 38 | /// # Safety | ||
| 39 | /// | ||
| 40 | /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` | ||
| 41 | /// to be called every time the `I` interrupt fires. | ||
| 42 | /// | ||
| 43 | /// This allows drivers to check bindings at compile-time. | ||
| 44 | pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} | ||
| 45 | |||
| 16 | /// Implementation detail, do not use outside embassy crates. | 46 | /// Implementation detail, do not use outside embassy crates. |
| 17 | #[doc(hidden)] | 47 | #[doc(hidden)] |
| 18 | pub struct DynHandler { | 48 | pub struct DynHandler { |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 3c5db5c7c..446b1f41a 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -95,14 +95,39 @@ pub mod wdt; | |||
| 95 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] | 95 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] |
| 96 | mod chip; | 96 | mod chip; |
| 97 | 97 | ||
| 98 | pub use chip::EASY_DMA_SIZE; | ||
| 99 | |||
| 100 | pub mod interrupt { | 98 | pub mod interrupt { |
| 101 | //! nRF interrupts for cortex-m devices. | 99 | //! Interrupt definitions and macros to bind them. |
| 102 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | 100 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; |
| 103 | pub use embassy_cortex_m::interrupt::*; | 101 | pub use embassy_cortex_m::interrupt::*; |
| 104 | 102 | ||
| 105 | pub use crate::chip::irqs::*; | 103 | pub use crate::chip::irqs::*; |
| 104 | |||
| 105 | /// Macro to bind interrupts to handlers. | ||
| 106 | /// | ||
| 107 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 108 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||
| 109 | /// prove at compile-time that the right interrupts have been bound. | ||
| 110 | // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. | ||
| 111 | #[macro_export] | ||
| 112 | macro_rules! bind_interrupts { | ||
| 113 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||
| 114 | $vis struct $name; | ||
| 115 | |||
| 116 | $( | ||
| 117 | #[allow(non_snake_case)] | ||
| 118 | #[no_mangle] | ||
| 119 | unsafe extern "C" fn $irq() { | ||
| 120 | $( | ||
| 121 | <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); | ||
| 122 | )* | ||
| 123 | } | ||
| 124 | |||
| 125 | $( | ||
| 126 | unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} | ||
| 127 | )* | ||
| 128 | )* | ||
| 129 | }; | ||
| 130 | } | ||
| 106 | } | 131 | } |
| 107 | 132 | ||
| 108 | // Reexports | 133 | // Reexports |
| @@ -111,7 +136,7 @@ pub mod interrupt { | |||
| 111 | pub use chip::pac; | 136 | pub use chip::pac; |
| 112 | #[cfg(not(feature = "unstable-pac"))] | 137 | #[cfg(not(feature = "unstable-pac"))] |
| 113 | pub(crate) use chip::pac; | 138 | pub(crate) use chip::pac; |
| 114 | pub use chip::{peripherals, Peripherals}; | 139 | pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; |
| 115 | pub use embassy_cortex_m::executor; | 140 | pub use embassy_cortex_m::executor; |
| 116 | pub use embassy_cortex_m::interrupt::_export::interrupt; | 141 | pub use embassy_cortex_m::interrupt::_export::interrupt; |
| 117 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 142 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
