Add InterruptHandler wrapper (#1299)
* Add InterruptHandler * Which takes the handler and a prio. * Updates the `#[handler]` macro to create this for us. * changelog
This commit is contained in:
parent
25f509ce74
commit
93d31e76d8
@ -368,6 +368,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
use darling::ast::NestedMeta;
|
||||
use proc_macro::Span;
|
||||
use proc_macro2::Ident;
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use proc_macro_error::abort;
|
||||
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};
|
||||
|
||||
@ -417,10 +419,28 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
.into();
|
||||
}
|
||||
|
||||
f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C");
|
||||
let root = Ident::new(
|
||||
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
|
||||
&name
|
||||
} else {
|
||||
"crate"
|
||||
},
|
||||
Span::call_site().into(),
|
||||
);
|
||||
|
||||
quote::quote_spanned!( original_span =>
|
||||
f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C");
|
||||
let orig = f.sig.ident;
|
||||
f.sig.ident = Ident::new(
|
||||
&format!("__esp_hal_internal_{}", orig),
|
||||
proc_macro2::Span::call_site(),
|
||||
);
|
||||
let new = f.sig.ident.clone();
|
||||
|
||||
quote::quote_spanned!(original_span =>
|
||||
#f
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #root::interrupt::Priority::min());
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Ensuring that the random number generator is TRNG. (#1200)
|
||||
- ESP32-C6: Add timer wakeup source for deepsleep (#1201)
|
||||
- Introduce `InterruptExecutor::spawner()` (#1211)
|
||||
- Add `InterruptHandler` struct, which couples interrupt handlers and their priority together (#1299)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@ -30,10 +30,13 @@ use procmacros::handler;
|
||||
#[cfg(any(adc, dac))]
|
||||
pub(crate) use crate::analog;
|
||||
pub(crate) use crate::gpio;
|
||||
use crate::peripherals::{GPIO, IO_MUX};
|
||||
#[cfg(any(xtensa, esp32c3))]
|
||||
pub(crate) use crate::rtc_pins;
|
||||
pub use crate::soc::gpio::*;
|
||||
use crate::{
|
||||
interrupt::InterruptHandler,
|
||||
peripherals::{GPIO, IO_MUX},
|
||||
};
|
||||
|
||||
/// Convenience type-alias for a no-pin / don't care - pin
|
||||
pub type NoPinType = Gpio0<Unknown>;
|
||||
@ -41,8 +44,7 @@ pub type NoPinType = Gpio0<Unknown>;
|
||||
/// Convenience constant for `Option::None` pin
|
||||
pub const NO_PIN: Option<NoPinType> = None;
|
||||
|
||||
static USER_INTERRUPT_HANDLER: Mutex<Cell<Option<unsafe extern "C" fn()>>> =
|
||||
Mutex::new(Cell::new(None));
|
||||
static USER_INTERRUPT_HANDLER: Mutex<Cell<Option<InterruptHandler>>> = Mutex::new(Cell::new(None));
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Event {
|
||||
@ -1872,9 +1874,9 @@ pub struct IO {
|
||||
}
|
||||
|
||||
impl IO {
|
||||
/// Initialize the I/O driver.
|
||||
pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self {
|
||||
gpio.bind_gpio_interrupt(gpio_interrupt_handler);
|
||||
|
||||
gpio.bind_gpio_interrupt(gpio_interrupt_handler.handler());
|
||||
let pins = gpio.split();
|
||||
|
||||
IO {
|
||||
@ -1883,6 +1885,15 @@ impl IO {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the I/O driver with a interrupt priority.
|
||||
///
|
||||
/// This decides the priority for the interrupt when only using async.
|
||||
pub fn new_with_priority(gpio: GPIO, io_mux: IO_MUX, prio: crate::interrupt::Priority) -> Self {
|
||||
crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, prio).unwrap();
|
||||
|
||||
Self::new(gpio, io_mux)
|
||||
}
|
||||
|
||||
/// Install the given interrupt handler replacing any previously set
|
||||
/// handler.
|
||||
///
|
||||
@ -1890,20 +1901,20 @@ impl IO {
|
||||
/// the internal async handler will run after. In that case it's
|
||||
/// important to not reset the interrupt status when mixing sync and
|
||||
/// async (i.e. using async wait) interrupt handling.
|
||||
pub fn set_interrupt_handler(&mut self, handler: unsafe extern "C" fn() -> ()) {
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
critical_section::with(|cs| {
|
||||
crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, handler.priority())
|
||||
.unwrap();
|
||||
USER_INTERRUPT_HANDLER.borrow(cs).set(Some(handler));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[handler]
|
||||
unsafe fn gpio_interrupt_handler() {
|
||||
fn gpio_interrupt_handler() {
|
||||
if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get())
|
||||
{
|
||||
unsafe {
|
||||
user_handler();
|
||||
}
|
||||
user_handler.call();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@ -3095,7 +3106,6 @@ mod asynch {
|
||||
use embedded_hal_async::digital::Wait;
|
||||
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
@ -60,3 +60,31 @@ pub use self::xtensa::*;
|
||||
mod riscv;
|
||||
#[cfg(xtensa)]
|
||||
mod xtensa;
|
||||
|
||||
/// An interrupt handler
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct InterruptHandler {
|
||||
f: extern "C" fn(),
|
||||
prio: Priority,
|
||||
}
|
||||
|
||||
impl InterruptHandler {
|
||||
pub const fn new(f: extern "C" fn(), prio: Priority) -> Self {
|
||||
Self { f, prio }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn handler(&self) -> extern "C" fn() {
|
||||
self.f
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn priority(&self) -> Priority {
|
||||
self.prio
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) extern "C" fn call(&self) {
|
||||
(self.f)()
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +88,7 @@ pub enum CpuInterrupt {
|
||||
}
|
||||
|
||||
/// Interrupt priority levels.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
@ -118,7 +119,7 @@ pub enum Priority {
|
||||
}
|
||||
|
||||
impl Priority {
|
||||
pub fn max() -> Priority {
|
||||
pub const fn max() -> Priority {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(clic))] {
|
||||
Priority::Priority15
|
||||
@ -128,7 +129,7 @@ impl Priority {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min() -> Priority {
|
||||
pub const fn min() -> Priority {
|
||||
Priority::Priority1
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,11 +241,11 @@ mod vectored {
|
||||
}
|
||||
|
||||
impl Priority {
|
||||
pub fn max() -> Priority {
|
||||
pub const fn max() -> Priority {
|
||||
Priority::Priority3
|
||||
}
|
||||
|
||||
pub fn min() -> Priority {
|
||||
pub const fn min() -> Priority {
|
||||
Priority::Priority1
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,9 +18,8 @@ use esp_hal::{
|
||||
clock::ClockControl,
|
||||
delay::Delay,
|
||||
gpio::{self, Event, Input, PullDown, IO},
|
||||
interrupt::{self, Priority},
|
||||
macros::ram,
|
||||
peripherals::{Interrupt, Peripherals},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
@ -46,12 +45,11 @@ fn main() -> ! {
|
||||
let mut button = io.pins.gpio0.into_pull_down_input();
|
||||
#[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))]
|
||||
let mut button = io.pins.gpio9.into_pull_down_input();
|
||||
button.listen(Event::FallingEdge);
|
||||
|
||||
critical_section::with(|cs| BUTTON.borrow_ref_mut(cs).replace(button));
|
||||
|
||||
interrupt::enable(Interrupt::GPIO, Priority::Priority2).unwrap();
|
||||
|
||||
critical_section::with(|cs| {
|
||||
button.listen(Event::FallingEdge);
|
||||
BUTTON.borrow_ref_mut(cs).replace(button)
|
||||
});
|
||||
led.set_high().unwrap();
|
||||
|
||||
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||
|
||||
Loading…
Reference in New Issue
Block a user