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