1
#![cfg_attr(docsrs, procmacros::doc_replace)]
2
//! # Software Interrupts
3
//!
4
//! [`SoftwareInterrupt`] raises or resets software interrupts with
5
//! [`raise()`][SoftwareInterrupt::raise] and [`reset()`][SoftwareInterrupt::reset].
6
#![cfg_attr(
7
    all(feature = "rt", multi_core),
8
    doc = "The HAL reserves `FROM_CPU_INTR0` and `FROM_CPU_INTR1` for inter-processor call (IPC)."
9
)]
10
#![cfg_attr(
11
    all(feature = "rt", single_core, context_switch_source = "from_cpu"),
12
    doc = "The HAL reserves `FROM_CPU_INTR0` to switch tasks."
13
)]
14
//! ## Examples
15
//!
16
//! ```rust, no_run
17
//! # {before_snippet}
18
//! // Take the interrupt you want to use.
19
//! let mut int0 = SoftwareInterrupt::new(peripherals.FROM_CPU_INTR2);
20
//!
21
//! // Set up the interrupt handler. Do this in a critical section so the global
22
//! // contains the interrupt object before the interrupt is triggered.
23
//! critical_section::with(|cs| {
24
//!     int0.set_interrupt_handler(swint0_handler);
25
//!     SWINT0.borrow_ref_mut(cs).replace(int0);
26
//! });
27
//! # {after_snippet}
28
//!
29
//! # use core::cell::RefCell;
30
//! # use critical_section::Mutex;
31
//! # use esp_hal::interrupt::software::SoftwareInterrupt;
32
//! // ... somewhere outside of your main function
33
//!
34
//! // Define a shared handle to the software interrupt.
35
//! static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<2>>>> = Mutex::new(RefCell::new(None));
36
//!
37
//! #[esp_hal::handler]
38
//! fn swint0_handler() {
39
//!     println!("SW interrupt0 handled");
40
//!
41
//!     // Clear the interrupt request.
42
//!     critical_section::with(|cs| {
43
//!         if let Some(swint) = SWINT0.borrow_ref(cs).as_ref() {
44
//!             swint.reset();
45
//!         }
46
//!     });
47
//! }
48
//! ```
49

            
50
use core::marker::PhantomData;
51

            
52
use crate::{
53
    interrupt::{self, InterruptConfigurable, InterruptHandler},
54
    peripherals::Interrupt,
55
    private::Sealed,
56
    system::Cpu,
57
};
58

            
59
/// A software interrupt can be triggered by software.
60
#[non_exhaustive]
61
pub struct SoftwareInterrupt<'d, const NUM: u8> {
62
    _lifetime: PhantomData<&'d mut ()>,
63
}
64

            
65
impl<'d, const NUM: u8> SoftwareInterrupt<'d, NUM> {
66
    /// Creates a new software interrupt driver.
67
    #[inline]
68
    pub const fn new(instance: impl Instance<NUM> + 'd) -> Self {
69
        core::mem::forget(instance); // needed to make `new` const
70
        Self {
71
            _lifetime: PhantomData,
72
        }
73
    }
74

            
75
    /// Sets the interrupt handler for this software-interrupt.
76
    #[instability::unstable]
77
    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
78
        let interrupt;
79

            
80
        for_each_sw_interrupt! {
81
            (all $( ($n:literal, $interrupt_name:ident, $f:ident) ),*) => {
82
                interrupt = match NUM {
83
                    $($n => Interrupt::$interrupt_name,)*
84
                    _ => unreachable!(),
85
                };
86
            };
87
        }
88

            
89
        for core in Cpu::other() {
90
            interrupt::disable(core, interrupt);
91
        }
92
6
        interrupt::bind_handler(interrupt, handler);
93
    }
94

            
95
    /// Triggers this software-interrupt.
96
    #[crate::ram]
97
2421
    pub fn raise(&self) {
98
        let regs = cfg_select! {
99
            soc_has_intpri => crate::peripherals::INTPRI::regs(),
100
            _ => crate::peripherals::SYSTEM::regs(),
101
        };
102
        let reg = regs.cpu_intr_from_cpu(NUM as usize);
103

            
104
        cfg_select! {
105
            xtensa => {
106
                reg.write(|w| w.cpu_intr().set_bit());
107
                // Read back to ensure the write is completed.
108
                _ = reg.read();
109
            }
110
            _ => {
111
                crate::interrupt::free(|| {
112
                    reg.write(|w| w.cpu_intr().set_bit());
113
                    // Wait for the interrupt to actually take effect.
114
2421
                    while !self.is_pending() {}
115
                });
116
            }
117
        }
118
2404
    }
119

            
120
    #[cfg(riscv)]
121
    fn is_pending(&self) -> bool {
122
        let interrupt;
123
        for_each_sw_interrupt! {
124
            (all $( ($n:literal, $interrupt_name:ident, $f:ident) ),*) => {
125
                interrupt = match NUM {
126
                    $($n => Interrupt::$interrupt_name,)*
127
                    _ => unreachable!(),
128
                };
129
            };
130
        }
131
        crate::interrupt::InterruptStatus::is_pending(interrupt)
132
    }
133

            
134
    /// Resets this software-interrupt.
135
    pub fn reset(&self) {
136
        cfg_select! {
137
            soc_has_intpri => {
138
                let regs = crate::peripherals::INTPRI::regs();
139
            }
140
            _ => {
141
                let regs = crate::peripherals::SYSTEM::regs();
142
            }
143
        }
144
        let reg;
145

            
146
        for_each_sw_interrupt! {
147
            (all $( ($n:literal, $i:ident, $f:ident) ),*) => {
148
                reg = match NUM {
149
                    $($n => regs.cpu_intr_from_cpu($n),)*
150
                    _ => unreachable!(),
151
                };
152
            };
153
        }
154

            
155
        reg.write(|w| w.cpu_intr().clear_bit());
156
    }
157
}
158

            
159
impl<const NUM: u8> crate::private::Sealed for SoftwareInterrupt<'_, NUM> {}
160

            
161
impl<const NUM: u8> InterruptConfigurable for SoftwareInterrupt<'_, NUM> {
162
    fn set_interrupt_handler(&mut self, handler: interrupt::InterruptHandler) {
163
        SoftwareInterrupt::set_interrupt_handler(self, handler);
164
    }
165
}
166

            
167
/// A software interrupt instance.
168
pub trait Instance<const NUM: u8>: Sealed {}
169

            
170
for_each_sw_interrupt! {
171
    ($n:literal, $i:ident, $field:ident) => {
172
        impl Instance<$n> for crate::peripherals::$i<'_> {}
173
    };
174
}