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 core::marker::PhantomData;
52
53use crate::interrupt::{InterruptConfigurable, InterruptHandler};
54
55/// A software interrupt can be triggered by software.
56#[non_exhaustive]
57pub struct SoftwareInterrupt<'d, const NUM: u8> {
58    _lifetime: PhantomData<&'d mut ()>,
59}
60
61impl<const NUM: u8> SoftwareInterrupt<'_, NUM> {
62    /// Unsafely create an instance of this peripheral out of thin air.
63    ///
64    /// # Safety
65    ///
66    /// You must ensure that you're only using one instance of this type at a
67    /// time.
68    #[inline]
69    pub unsafe fn steal() -> Self {
70        Self {
71            _lifetime: PhantomData,
72        }
73    }
74
75    /// Creates a new peripheral reference with a shorter lifetime.
76    ///
77    /// Use this method if you would like to keep working with the peripheral
78    /// after you dropped the driver that consumes this.
79    pub fn reborrow(&mut self) -> SoftwareInterrupt<'_, NUM> {
80        unsafe { SoftwareInterrupt::steal() }
81    }
82
83    /// Sets the interrupt handler for this software-interrupt
84    #[instability::unstable]
85    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
86        let interrupt = match NUM {
87            0 => crate::peripherals::Interrupt::FROM_CPU_INTR0,
88            1 => crate::peripherals::Interrupt::FROM_CPU_INTR1,
89            2 => crate::peripherals::Interrupt::FROM_CPU_INTR2,
90            3 => crate::peripherals::Interrupt::FROM_CPU_INTR3,
91            _ => unreachable!(),
92        };
93
94        for core in crate::system::Cpu::other() {
95            crate::interrupt::disable(core, interrupt);
96        }
97        unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
98        unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
99    }
100
101    /// Trigger this software-interrupt
102    pub fn raise(&self) {
103        cfg_if::cfg_if! {
104            if #[cfg(any(esp32c6, esp32h2))] {
105                let system = crate::peripherals::INTPRI::regs();
106            } else {
107                let system = crate::peripherals::SYSTEM::regs();
108            }
109        }
110
111        match NUM {
112            0 => system
113                .cpu_intr_from_cpu_0()
114                .write(|w| w.cpu_intr_from_cpu_0().set_bit()),
115            1 => system
116                .cpu_intr_from_cpu_1()
117                .write(|w| w.cpu_intr_from_cpu_1().set_bit()),
118            2 => system
119                .cpu_intr_from_cpu_2()
120                .write(|w| w.cpu_intr_from_cpu_2().set_bit()),
121            3 => system
122                .cpu_intr_from_cpu_3()
123                .write(|w| w.cpu_intr_from_cpu_3().set_bit()),
124            _ => unreachable!(),
125        };
126    }
127
128    /// Resets this software-interrupt
129    pub fn reset(&self) {
130        cfg_if::cfg_if! {
131            if #[cfg(any(esp32c6, esp32h2))] {
132                let system = crate::peripherals::INTPRI::regs();
133            } else {
134                let system = crate::peripherals::SYSTEM::regs();
135            }
136        }
137
138        match NUM {
139            0 => system
140                .cpu_intr_from_cpu_0()
141                .write(|w| w.cpu_intr_from_cpu_0().clear_bit()),
142            1 => system
143                .cpu_intr_from_cpu_1()
144                .write(|w| w.cpu_intr_from_cpu_1().clear_bit()),
145            2 => system
146                .cpu_intr_from_cpu_2()
147                .write(|w| w.cpu_intr_from_cpu_2().clear_bit()),
148            3 => system
149                .cpu_intr_from_cpu_3()
150                .write(|w| w.cpu_intr_from_cpu_3().clear_bit()),
151            _ => unreachable!(),
152        };
153    }
154}
155
156impl<const NUM: u8> crate::private::Sealed for SoftwareInterrupt<'_, NUM> {}
157
158impl<const NUM: u8> InterruptConfigurable for SoftwareInterrupt<'_, NUM> {
159    fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
160        SoftwareInterrupt::set_interrupt_handler(self, handler);
161    }
162}
163
164/// This gives access to the available software interrupts.
165///
166/// This struct contains several instances of software interrupts that can be
167/// used for signaling between different parts of a program or system. Each
168/// interrupt is identified by an index (0 to 3).
169#[cfg_attr(
170    multi_core,
171    doc = r#"
172
173Please note: Software interrupt 3 is reserved
174for inter-processor communication when using
175`esp-hal-embassy`."#
176)]
177#[non_exhaustive]
178pub struct SoftwareInterruptControl<'d> {
179    /// Software interrupt 0.
180    pub software_interrupt0: SoftwareInterrupt<'d, 0>,
181    /// Software interrupt 1.
182    pub software_interrupt1: SoftwareInterrupt<'d, 1>,
183    /// Software interrupt 2. Not available when using esp-wifi's builtin
184    /// scheduler on RISC-V architectures.
185    #[cfg(not(all(feature = "__esp_wifi_builtin_scheduler", riscv)))]
186    pub software_interrupt2: SoftwareInterrupt<'d, 2>,
187    #[cfg(not(all(feature = "__esp_hal_embassy", multi_core)))]
188    /// Software interrupt 3. Not available when using `esp-hal-embassy`,
189    /// on multi-core systems.
190    pub software_interrupt3: SoftwareInterrupt<'d, 3>,
191}
192
193impl<'d> SoftwareInterruptControl<'d> {
194    /// Create a new instance of the software interrupt control.
195    pub fn new(_peripheral: crate::peripherals::SW_INTERRUPT<'d>) -> Self {
196        SoftwareInterruptControl {
197            software_interrupt0: SoftwareInterrupt {
198                _lifetime: PhantomData,
199            },
200            software_interrupt1: SoftwareInterrupt {
201                _lifetime: PhantomData,
202            },
203            #[cfg(not(all(feature = "__esp_wifi_builtin_scheduler", riscv)))]
204            software_interrupt2: SoftwareInterrupt {
205                _lifetime: PhantomData,
206            },
207            #[cfg(not(all(feature = "__esp_hal_embassy", multi_core)))]
208            software_interrupt3: SoftwareInterrupt {
209                _lifetime: PhantomData,
210            },
211        }
212    }
213}