esp_hal/interrupt/
software.rs

1//! # Software Interrupts
2//!
3//! The [`SoftwareInterruptControl`] struct gives access to the available
4//! software interrupts.
5//!
6//! The [`SoftwareInterrupt`] struct allows raising or resetting software
7//! interrupts using the [`raise()`][SoftwareInterrupt::raise] and
8//! [`reset()`][SoftwareInterrupt::reset] methods.
9//!
10//! ## Examples
11//!
12//! ```rust, no_run
13#![doc = crate::before_snippet!()]
14//! let sw_ints =
15//!     SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
16//!
17//! // Take the interrupt you want to use.
18//! let mut int0 = sw_ints.software_interrupt0;
19//!
20//! // Set up the interrupt handler. Do this in a critical section so the global
21//! // contains the interrupt object before the interrupt is triggered.
22//! critical_section::with(|cs| {
23//!     int0.set_interrupt_handler(swint0_handler);
24//!     SWINT0.borrow_ref_mut(cs).replace(int0);
25//! });
26//! # Ok(())
27//! # }
28//!
29//! # use core::cell::RefCell;
30//! # use critical_section::Mutex;
31//! # use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl};
32//! // ... somewhere outside of your main function
33//!
34//! // Define a shared handle to the software interrupt.
35//! static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<0>>>> =
36//!     Mutex::new(RefCell::new(None));
37//!
38//! #[handler]
39//! fn swint0_handler() {
40//!     println!("SW interrupt0 handled");
41//!
42//!     // Clear the interrupt request.
43//!     critical_section::with(|cs| {
44//!         if let Some(swint) = SWINT0.borrow_ref(cs).as_ref() {
45//!             swint.reset();
46//!         }
47//!     });
48//! }
49//! ```
50
51use crate::interrupt::{InterruptConfigurable, InterruptHandler};
52
53/// A software interrupt can be triggered by software.
54#[non_exhaustive]
55pub struct SoftwareInterrupt<const NUM: u8>;
56
57impl<const NUM: u8> SoftwareInterrupt<NUM> {
58    /// Sets the interrupt handler for this software-interrupt
59    #[instability::unstable]
60    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
61        let interrupt = match NUM {
62            0 => crate::peripherals::Interrupt::FROM_CPU_INTR0,
63            1 => crate::peripherals::Interrupt::FROM_CPU_INTR1,
64            2 => crate::peripherals::Interrupt::FROM_CPU_INTR2,
65            3 => crate::peripherals::Interrupt::FROM_CPU_INTR3,
66            _ => unreachable!(),
67        };
68
69        for core in crate::system::Cpu::other() {
70            crate::interrupt::disable(core, interrupt);
71        }
72        unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
73        unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
74    }
75
76    /// Trigger this software-interrupt
77    pub fn raise(&self) {
78        cfg_if::cfg_if! {
79            if #[cfg(any(esp32c6, esp32h2))] {
80                let system = crate::peripherals::INTPRI::regs();
81            } else {
82                let system = crate::peripherals::SYSTEM::regs();
83            }
84        }
85
86        match NUM {
87            0 => system
88                .cpu_intr_from_cpu_0()
89                .write(|w| w.cpu_intr_from_cpu_0().set_bit()),
90            1 => system
91                .cpu_intr_from_cpu_1()
92                .write(|w| w.cpu_intr_from_cpu_1().set_bit()),
93            2 => system
94                .cpu_intr_from_cpu_2()
95                .write(|w| w.cpu_intr_from_cpu_2().set_bit()),
96            3 => system
97                .cpu_intr_from_cpu_3()
98                .write(|w| w.cpu_intr_from_cpu_3().set_bit()),
99            _ => unreachable!(),
100        };
101    }
102
103    /// Resets this software-interrupt
104    pub fn reset(&self) {
105        cfg_if::cfg_if! {
106            if #[cfg(any(esp32c6, esp32h2))] {
107                let system = crate::peripherals::INTPRI::regs();
108            } else {
109                let system = crate::peripherals::SYSTEM::regs();
110            }
111        }
112
113        match NUM {
114            0 => system
115                .cpu_intr_from_cpu_0()
116                .write(|w| w.cpu_intr_from_cpu_0().clear_bit()),
117            1 => system
118                .cpu_intr_from_cpu_1()
119                .write(|w| w.cpu_intr_from_cpu_1().clear_bit()),
120            2 => system
121                .cpu_intr_from_cpu_2()
122                .write(|w| w.cpu_intr_from_cpu_2().clear_bit()),
123            3 => system
124                .cpu_intr_from_cpu_3()
125                .write(|w| w.cpu_intr_from_cpu_3().clear_bit()),
126            _ => unreachable!(),
127        };
128    }
129
130    /// Unsafely create an instance of this peripheral out of thin air.
131    ///
132    /// # Safety
133    ///
134    /// You must ensure that you're only using one instance of this type at a
135    /// time.
136    #[inline]
137    pub unsafe fn steal() -> Self {
138        Self
139    }
140}
141
142impl<const NUM: u8> crate::peripheral::Peripheral for SoftwareInterrupt<NUM> {
143    type P = SoftwareInterrupt<NUM>;
144
145    #[inline]
146    unsafe fn clone_unchecked(&self) -> Self::P {
147        Self::steal()
148    }
149}
150
151impl<const NUM: u8> crate::private::Sealed for SoftwareInterrupt<NUM> {}
152
153impl<const NUM: u8> InterruptConfigurable for SoftwareInterrupt<NUM> {
154    fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
155        SoftwareInterrupt::set_interrupt_handler(self, handler);
156    }
157}
158
159/// This gives access to the available software interrupts.
160///
161/// This struct contains several instances of software interrupts that can be
162/// used for signaling between different parts of a program or system. Each
163/// interrupt is identified by an index (0 to 3).
164#[cfg_attr(
165    multi_core,
166    doc = r#"
167
168Please note: Software interrupt 3 is reserved
169for inter-processor communication when using
170`esp-hal-embassy`."#
171)]
172#[non_exhaustive]
173pub struct SoftwareInterruptControl {
174    /// Software interrupt 0.
175    pub software_interrupt0: SoftwareInterrupt<0>,
176    /// Software interrupt 1.
177    pub software_interrupt1: SoftwareInterrupt<1>,
178    /// Software interrupt 2.
179    pub software_interrupt2: SoftwareInterrupt<2>,
180    #[cfg(not(all(feature = "__esp_hal_embassy", multi_core)))]
181    /// Software interrupt 3. Only available when not using `esp-hal-embassy`,
182    /// or on single-core systems.
183    pub software_interrupt3: SoftwareInterrupt<3>,
184}
185
186impl SoftwareInterruptControl {
187    /// Create a new instance of the software interrupt control.
188    pub fn new(_peripheral: crate::peripherals::SW_INTERRUPT) -> Self {
189        SoftwareInterruptControl {
190            software_interrupt0: SoftwareInterrupt {},
191            software_interrupt1: SoftwareInterrupt {},
192            software_interrupt2: SoftwareInterrupt {},
193            #[cfg(not(all(feature = "__esp_hal_embassy", multi_core)))]
194            software_interrupt3: SoftwareInterrupt {},
195        }
196    }
197}