esp_hal/interrupt/
xtensa.rs

1//! Interrupt handling
2
3use procmacros::ram;
4use xtensa_lx::interrupt;
5#[cfg(esp32)]
6pub(crate) use xtensa_lx::interrupt::free;
7#[cfg(feature = "rt")]
8use xtensa_lx_rt::exception::Context;
9
10pub use self::vectored::*;
11use super::InterruptStatus;
12use crate::{pac, peripherals::Interrupt, system::Cpu};
13
14/// Interrupt Error
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum Error {
18    /// The given interrupt is not a valid interrupt
19    InvalidInterrupt,
20    /// The CPU interrupt is a reserved interrupt
21    CpuInterruptReserved,
22}
23
24/// Enumeration of available CPU interrupts
25///
26/// It's possible to create one handler per priority level. (e.g
27/// `level1_interrupt`)
28#[derive(Debug, Copy, Clone)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[repr(u32)]
31pub enum CpuInterrupt {
32    /// Level-triggered interrupt with priority 1.
33    Interrupt0LevelPriority1 = 0,
34    /// Level-triggered interrupt with priority 1.
35    Interrupt1LevelPriority1,
36    /// Level-triggered interrupt with priority 1.
37    Interrupt2LevelPriority1,
38    /// Level-triggered interrupt with priority 1.
39    Interrupt3LevelPriority1,
40    /// Level-triggered interrupt with priority 1.
41    Interrupt4LevelPriority1,
42    /// Level-triggered interrupt with priority 1.
43    Interrupt5LevelPriority1,
44    /// Timer 0 interrupt with priority 1.
45    Interrupt6Timer0Priority1,
46    /// Software-triggered interrupt with priority 1.
47    Interrupt7SoftwarePriority1,
48    /// Level-triggered interrupt with priority 1.
49    Interrupt8LevelPriority1,
50    /// Level-triggered interrupt with priority 1.
51    Interrupt9LevelPriority1,
52    /// Edge-triggered interrupt with priority 1.
53    Interrupt10EdgePriority1,
54    /// Profiling-related interrupt with priority 3.
55    Interrupt11ProfilingPriority3,
56    /// Level-triggered interrupt with priority 1.
57    Interrupt12LevelPriority1,
58    /// Level-triggered interrupt with priority 1.
59    Interrupt13LevelPriority1,
60    /// Non-maskable interrupt (NMI) with priority 7.
61    Interrupt14NmiPriority7,
62    /// Timer 1 interrupt with priority 3.
63    Interrupt15Timer1Priority3,
64    /// Timer 2 interrupt with priority 5.
65    Interrupt16Timer2Priority5,
66    /// Level-triggered interrupt with priority 1.
67    Interrupt17LevelPriority1,
68    /// Level-triggered interrupt with priority 1.
69    Interrupt18LevelPriority1,
70    /// Level-triggered interrupt with priority 2.
71    Interrupt19LevelPriority2,
72    /// Level-triggered interrupt with priority 2.
73    Interrupt20LevelPriority2,
74    /// Level-triggered interrupt with priority 2.
75    Interrupt21LevelPriority2,
76    /// Edge-triggered interrupt with priority 3.
77    Interrupt22EdgePriority3,
78    /// Level-triggered interrupt with priority 3.
79    Interrupt23LevelPriority3,
80    /// Level-triggered interrupt with priority 4.
81    Interrupt24LevelPriority4,
82    /// Level-triggered interrupt with priority 4.
83    Interrupt25LevelPriority4,
84    /// Level-triggered interrupt with priority 5.
85    Interrupt26LevelPriority5,
86    /// Level-triggered interrupt with priority 3.
87    Interrupt27LevelPriority3,
88    /// Edge-triggered interrupt with priority 4.
89    Interrupt28EdgePriority4,
90    /// Software-triggered interrupt with priority 3.
91    Interrupt29SoftwarePriority3,
92    /// Edge-triggered interrupt with priority 4.
93    Interrupt30EdgePriority4,
94    /// Edge-triggered interrupt with priority 5.
95    Interrupt31EdgePriority5,
96}
97
98impl CpuInterrupt {
99    fn from_u32(n: u32) -> Option<Self> {
100        if n < 32 {
101            Some(unsafe { core::mem::transmute::<u32, Self>(n) })
102        } else {
103            None
104        }
105    }
106
107    fn is_internal(self) -> bool {
108        matches!(
109            self,
110            Self::Interrupt6Timer0Priority1
111                | Self::Interrupt7SoftwarePriority1
112                | Self::Interrupt11ProfilingPriority3
113                | Self::Interrupt15Timer1Priority3
114                | Self::Interrupt16Timer2Priority5
115                | Self::Interrupt29SoftwarePriority3
116        )
117    }
118
119    fn is_peripheral(self) -> bool {
120        !self.is_internal()
121    }
122}
123
124/// The interrupts reserved by the HAL
125#[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
126pub static RESERVED_INTERRUPTS: &[u32] = &[
127    CpuInterrupt::Interrupt1LevelPriority1 as _,
128    CpuInterrupt::Interrupt19LevelPriority2 as _,
129    CpuInterrupt::Interrupt23LevelPriority3 as _,
130    CpuInterrupt::Interrupt10EdgePriority1 as _,
131    CpuInterrupt::Interrupt22EdgePriority3 as _,
132];
133
134pub(crate) fn setup_interrupts() {
135    // disable all known interrupts
136    // at least after the 2nd stage bootloader there are some interrupts enabled
137    // (e.g. UART)
138    for peripheral_interrupt in 0..255 {
139        Interrupt::try_from(peripheral_interrupt)
140            .map(|intr| {
141                #[cfg(multi_core)]
142                disable(Cpu::AppCpu, intr);
143                disable(Cpu::ProCpu, intr);
144            })
145            .ok();
146    }
147}
148
149/// Enable an interrupt by directly binding it to a available CPU interrupt
150///
151/// Unless you are sure, you most likely want to use [`enable`] instead.
152///
153/// Trying using a reserved interrupt from [`RESERVED_INTERRUPTS`] will return
154/// an error.
155pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Result<(), Error> {
156    if RESERVED_INTERRUPTS.contains(&(cpu_interrupt as _)) {
157        return Err(Error::CpuInterruptReserved);
158    }
159    unsafe {
160        map(Cpu::current(), interrupt, cpu_interrupt);
161
162        xtensa_lx::interrupt::enable_mask(
163            xtensa_lx::interrupt::get_mask() | (1 << cpu_interrupt as u32),
164        );
165    }
166    Ok(())
167}
168
169/// Assign a peripheral interrupt to an CPU interrupt
170///
171/// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt
172/// still needs to be enabled afterwards
173///
174/// # Safety
175///
176/// Do not use CPU interrupts in the [`RESERVED_INTERRUPTS`].
177pub unsafe fn map(cpu: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
178    let interrupt_number = interrupt as usize;
179    let cpu_interrupt_number = which as u32;
180    match cpu {
181        Cpu::ProCpu => unsafe {
182            (*core0_interrupt_peripheral())
183                .core_0_intr_map(interrupt_number)
184                .write(|w| w.bits(cpu_interrupt_number));
185        },
186        #[cfg(multi_core)]
187        Cpu::AppCpu => unsafe {
188            (*core1_interrupt_peripheral())
189                .core_1_intr_map(interrupt_number)
190                .write(|w| w.bits(cpu_interrupt_number));
191        },
192    }
193}
194
195/// Get cpu interrupt assigned to peripheral interrupt
196pub(crate) fn bound_cpu_interrupt_for(cpu: Cpu, interrupt: Interrupt) -> Option<CpuInterrupt> {
197    let cpu_intr = match cpu {
198        Cpu::ProCpu => unsafe {
199            (*core0_interrupt_peripheral())
200                .core_0_intr_map(interrupt as usize)
201                .read()
202                .bits()
203        },
204        #[cfg(multi_core)]
205        Cpu::AppCpu => unsafe {
206            (*core1_interrupt_peripheral())
207                .core_1_intr_map(interrupt as usize)
208                .read()
209                .bits()
210        },
211    };
212    let cpu_intr = CpuInterrupt::from_u32(cpu_intr)?;
213
214    if cpu_intr.is_peripheral() {
215        Some(cpu_intr)
216    } else {
217        None
218    }
219}
220
221/// Disable the given peripheral interrupt
222pub fn disable(core: Cpu, interrupt: Interrupt) {
223    unsafe { map(core, interrupt, CpuInterrupt::Interrupt16Timer2Priority5) }
224}
225
226/// Clear the given CPU interrupt
227pub fn clear(_core: Cpu, which: CpuInterrupt) {
228    unsafe {
229        xtensa_lx::interrupt::clear(1 << which as u32);
230    }
231}
232
233/// Get status of peripheral interrupts
234#[cfg(interrupts_status_registers = "3")]
235pub fn status(core: Cpu) -> InterruptStatus {
236    unsafe {
237        match core {
238            Cpu::ProCpu => InterruptStatus::from(
239                (*core0_interrupt_peripheral())
240                    .core_0_intr_status(0)
241                    .read()
242                    .bits(),
243                (*core0_interrupt_peripheral())
244                    .core_0_intr_status(1)
245                    .read()
246                    .bits(),
247                (*core0_interrupt_peripheral())
248                    .core_0_intr_status(2)
249                    .read()
250                    .bits(),
251            ),
252            #[cfg(multi_core)]
253            Cpu::AppCpu => InterruptStatus::from(
254                (*core1_interrupt_peripheral())
255                    .core_1_intr_status(0)
256                    .read()
257                    .bits(),
258                (*core1_interrupt_peripheral())
259                    .core_1_intr_status(1)
260                    .read()
261                    .bits(),
262                (*core1_interrupt_peripheral())
263                    .core_1_intr_status(2)
264                    .read()
265                    .bits(),
266            ),
267        }
268    }
269}
270
271/// Get status of peripheral interrupts
272#[cfg(interrupts_status_registers = "4")]
273pub fn status(core: Cpu) -> InterruptStatus {
274    unsafe {
275        match core {
276            Cpu::ProCpu => InterruptStatus::from(
277                (*core0_interrupt_peripheral())
278                    .core_0_intr_status(0)
279                    .read()
280                    .bits(),
281                (*core0_interrupt_peripheral())
282                    .core_0_intr_status(1)
283                    .read()
284                    .bits(),
285                (*core0_interrupt_peripheral())
286                    .core_0_intr_status(2)
287                    .read()
288                    .bits(),
289                (*core0_interrupt_peripheral())
290                    .core_0_intr_status(3)
291                    .read()
292                    .bits(),
293            ),
294            #[cfg(multi_core)]
295            Cpu::AppCpu => InterruptStatus::from(
296                (*core1_interrupt_peripheral())
297                    .core_1_intr_status(0)
298                    .read()
299                    .bits(),
300                (*core1_interrupt_peripheral())
301                    .core_1_intr_status(1)
302                    .read()
303                    .bits(),
304                (*core1_interrupt_peripheral())
305                    .core_1_intr_status(2)
306                    .read()
307                    .bits(),
308                (*core1_interrupt_peripheral())
309                    .core_1_intr_status(3)
310                    .read()
311                    .bits(),
312            ),
313        }
314    }
315}
316
317#[cfg(esp32)]
318unsafe fn core0_interrupt_peripheral() -> *const crate::pac::dport::RegisterBlock {
319    pac::DPORT::PTR
320}
321
322#[cfg(esp32)]
323unsafe fn core1_interrupt_peripheral() -> *const crate::pac::dport::RegisterBlock {
324    pac::DPORT::PTR
325}
326
327#[cfg(any(esp32s2, esp32s3))]
328unsafe fn core0_interrupt_peripheral() -> *const crate::pac::interrupt_core0::RegisterBlock {
329    pac::INTERRUPT_CORE0::PTR
330}
331
332#[cfg(esp32s3)]
333unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::RegisterBlock {
334    pac::INTERRUPT_CORE1::PTR
335}
336
337/// Get the current run level (the level below which interrupts are masked).
338pub fn current_runlevel() -> Priority {
339    let ps: u32;
340    unsafe { core::arch::asm!("rsr.ps {0}", out(reg) ps) };
341
342    let prev_interrupt_priority = ps as u8 & 0x0F;
343
344    unwrap!(Priority::try_from(prev_interrupt_priority))
345}
346
347/// Changes the current run level (the level below which interrupts are
348/// masked), and returns the previous run level.
349///
350/// # Safety
351///
352/// This function must only be used to raise the runlevel and to restore it
353/// to a previous value. It must not be used to arbitrarily lower the
354/// runlevel.
355pub(crate) unsafe fn change_current_runlevel(level: Priority) -> Priority {
356    let token: u32;
357    unsafe {
358        match level {
359            Priority::None => core::arch::asm!("rsil {0}, 0", out(reg) token),
360            Priority::Priority1 => core::arch::asm!("rsil {0}, 1", out(reg) token),
361            Priority::Priority2 => core::arch::asm!("rsil {0}, 2", out(reg) token),
362            Priority::Priority3 => core::arch::asm!("rsil {0}, 3", out(reg) token),
363        };
364    }
365
366    let prev_interrupt_priority = token as u8 & 0x0F;
367
368    unwrap!(Priority::try_from(prev_interrupt_priority))
369}
370
371mod vectored {
372    use super::*;
373
374    /// Interrupt priority levels.
375    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
376    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
377    #[repr(u8)]
378    pub enum Priority {
379        /// No priority.
380        None = 0,
381        /// Priority level 1.
382        Priority1,
383        /// Priority level 2.
384        Priority2,
385        /// Priority level 3.
386        Priority3,
387    }
388
389    impl Priority {
390        /// Maximum interrupt priority
391        pub const fn max() -> Priority {
392            Priority::Priority3
393        }
394
395        /// Minimum interrupt priority
396        pub const fn min() -> Priority {
397            Priority::Priority1
398        }
399    }
400
401    impl TryFrom<u32> for Priority {
402        type Error = Error;
403
404        fn try_from(value: u32) -> Result<Self, Self::Error> {
405            match value {
406                0 => Ok(Priority::None),
407                1 => Ok(Priority::Priority1),
408                2 => Ok(Priority::Priority2),
409                3 => Ok(Priority::Priority3),
410                _ => Err(Error::InvalidInterrupt),
411            }
412        }
413    }
414
415    impl TryFrom<u8> for Priority {
416        type Error = Error;
417
418        fn try_from(value: u8) -> Result<Self, Self::Error> {
419            Self::try_from(value as u32)
420        }
421    }
422
423    impl CpuInterrupt {
424        #[inline]
425        fn level(&self) -> Priority {
426            match self {
427                CpuInterrupt::Interrupt0LevelPriority1
428                | CpuInterrupt::Interrupt1LevelPriority1
429                | CpuInterrupt::Interrupt2LevelPriority1
430                | CpuInterrupt::Interrupt3LevelPriority1
431                | CpuInterrupt::Interrupt4LevelPriority1
432                | CpuInterrupt::Interrupt5LevelPriority1
433                | CpuInterrupt::Interrupt6Timer0Priority1
434                | CpuInterrupt::Interrupt7SoftwarePriority1
435                | CpuInterrupt::Interrupt8LevelPriority1
436                | CpuInterrupt::Interrupt9LevelPriority1
437                | CpuInterrupt::Interrupt10EdgePriority1
438                | CpuInterrupt::Interrupt12LevelPriority1
439                | CpuInterrupt::Interrupt13LevelPriority1
440                | CpuInterrupt::Interrupt17LevelPriority1
441                | CpuInterrupt::Interrupt18LevelPriority1 => Priority::Priority1,
442
443                CpuInterrupt::Interrupt19LevelPriority2
444                | CpuInterrupt::Interrupt20LevelPriority2
445                | CpuInterrupt::Interrupt21LevelPriority2 => Priority::Priority2,
446
447                CpuInterrupt::Interrupt11ProfilingPriority3
448                | CpuInterrupt::Interrupt15Timer1Priority3
449                | CpuInterrupt::Interrupt22EdgePriority3
450                | CpuInterrupt::Interrupt27LevelPriority3
451                | CpuInterrupt::Interrupt29SoftwarePriority3
452                | CpuInterrupt::Interrupt23LevelPriority3 => Priority::Priority3,
453
454                // we direct these to None because we do not support interrupts at this level
455                // through Rust
456                CpuInterrupt::Interrupt24LevelPriority4
457                | CpuInterrupt::Interrupt25LevelPriority4
458                | CpuInterrupt::Interrupt28EdgePriority4
459                | CpuInterrupt::Interrupt30EdgePriority4
460                | CpuInterrupt::Interrupt31EdgePriority5
461                | CpuInterrupt::Interrupt16Timer2Priority5
462                | CpuInterrupt::Interrupt26LevelPriority5
463                | CpuInterrupt::Interrupt14NmiPriority7 => Priority::None,
464            }
465        }
466    }
467
468    /// Get the interrupts configured for the core
469    #[inline(always)]
470    pub(crate) fn configured_interrupts(
471        core: Cpu,
472        status: InterruptStatus,
473        level: u32,
474    ) -> InterruptStatus {
475        unsafe {
476            let intr_map_base = match core {
477                Cpu::ProCpu => (*core0_interrupt_peripheral()).core_0_intr_map(0).as_ptr(),
478                #[cfg(multi_core)]
479                Cpu::AppCpu => (*core1_interrupt_peripheral()).core_1_intr_map(0).as_ptr(),
480            };
481
482            let mut res = InterruptStatus::empty();
483
484            for interrupt_nr in status.iterator() {
485                let i = interrupt_nr as isize;
486                let cpu_interrupt = intr_map_base.offset(i).read_volatile();
487                // safety: cast is safe because of repr(u32)
488                let cpu_interrupt = core::mem::transmute::<u32, CpuInterrupt>(cpu_interrupt);
489                let int_level = cpu_interrupt.level() as u32;
490
491                if int_level == level {
492                    res.set(interrupt_nr);
493                }
494            }
495
496            res
497        }
498    }
499
500    /// Enable the given peripheral interrupt
501    pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
502        enable_on_cpu(Cpu::current(), interrupt, level)
503    }
504
505    pub(crate) fn enable_on_cpu(
506        cpu: Cpu,
507        interrupt: Interrupt,
508        level: Priority,
509    ) -> Result<(), Error> {
510        let cpu_interrupt =
511            interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;
512
513        unsafe {
514            map(cpu, interrupt, cpu_interrupt);
515
516            xtensa_lx::interrupt::enable_mask(
517                xtensa_lx::interrupt::get_mask() | (1 << cpu_interrupt as u32),
518            );
519        }
520        Ok(())
521    }
522
523    /// Binds the given interrupt to the given handler.
524    ///
525    /// # Safety
526    ///
527    /// This will replace any previously bound interrupt handler
528    pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) {
529        let ptr = unsafe {
530            &pac::__INTERRUPTS[interrupt as usize]._handler as *const _
531                as *mut unsafe extern "C" fn()
532        };
533        unsafe {
534            ptr.write_volatile(handler);
535        }
536    }
537
538    /// Returns the currently bound interrupt handler.
539    pub fn bound_handler(interrupt: Interrupt) -> Option<unsafe extern "C" fn()> {
540        unsafe {
541            let addr = pac::__INTERRUPTS[interrupt as usize]._handler;
542            if addr as usize == 0 {
543                return None;
544            }
545            Some(addr)
546        }
547    }
548
549    fn interrupt_level_to_cpu_interrupt(
550        level: Priority,
551        is_edge: bool,
552    ) -> Result<CpuInterrupt, Error> {
553        Ok(if is_edge {
554            match level {
555                Priority::None => return Err(Error::InvalidInterrupt),
556                Priority::Priority1 => CpuInterrupt::Interrupt10EdgePriority1,
557                Priority::Priority2 => return Err(Error::InvalidInterrupt),
558                Priority::Priority3 => CpuInterrupt::Interrupt22EdgePriority3,
559            }
560        } else {
561            match level {
562                Priority::None => return Err(Error::InvalidInterrupt),
563                Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1,
564                Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2,
565                Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3,
566            }
567        })
568    }
569
570    // TODO use CpuInterrupt::LevelX.mask() // TODO make it const
571    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
572    pub(crate) static CPU_INTERRUPT_LEVELS: [u32; 8] = [
573        0b_0000_0000_0000_0000_0000_0000_0000_0000, // Dummy level 0
574        0b_0000_0000_0000_0110_0011_0111_1111_1111, // Level_1
575        0b_0000_0000_0011_1000_0000_0000_0000_0000, // Level 2
576        0b_0010_1000_1100_0000_1000_1000_0000_0000, // Level 3
577        0b_0101_0011_0000_0000_0000_0000_0000_0000, // Level 4
578        0b_1000_0100_0000_0001_0000_0000_0000_0000, // Level 5
579        0b_0000_0000_0000_0000_0000_0000_0000_0000, // Level 6
580        0b_0000_0000_0000_0000_0100_0000_0000_0000, // Level 7
581    ];
582    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
583    pub(crate) static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
584    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
585    pub(crate) static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
586
587    #[cfg(esp32)]
588    pub(crate) mod chip_specific {
589        use super::*;
590        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
591        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
592            0b0000_0000_0000_0000_0000_0000_0000_0000,
593            0b1111_1100_0000_0000_0000_0000_0000_0000,
594            0b0000_0000_0000_0000_0000_0000_0000_0011,
595        );
596        #[inline]
597        pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
598            [
599                Interrupt::TG0_T0_EDGE,
600                Interrupt::TG0_T1_EDGE,
601                Interrupt::TG0_WDT_EDGE,
602                Interrupt::TG0_LACT_EDGE,
603                Interrupt::TG1_T0_EDGE,
604                Interrupt::TG1_T1_EDGE,
605                Interrupt::TG1_WDT_EDGE,
606                Interrupt::TG1_LACT_EDGE,
607            ]
608            .contains(&interrupt)
609        }
610    }
611
612    #[cfg(esp32s2)]
613    pub(crate) mod chip_specific {
614        use super::*;
615        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
616        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
617            0b0000_0000_0000_0000_0000_0000_0000_0000,
618            0b1100_0000_0000_0000_0000_0000_0000_0000,
619            0b0000_0000_0000_0000_0000_0011_1011_1111,
620        );
621        #[inline]
622        pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
623            [
624                Interrupt::TG0_T0_EDGE,
625                Interrupt::TG0_T1_EDGE,
626                Interrupt::TG0_WDT_EDGE,
627                Interrupt::TG0_LACT_EDGE,
628                Interrupt::TG1_T0_EDGE,
629                Interrupt::TG1_T1_EDGE,
630                Interrupt::TG1_WDT_EDGE,
631                Interrupt::TG1_LACT_EDGE,
632                Interrupt::SYSTIMER_TARGET0,
633                Interrupt::SYSTIMER_TARGET1,
634                Interrupt::SYSTIMER_TARGET2,
635            ]
636            .contains(&interrupt)
637        }
638    }
639
640    #[cfg(esp32s3)]
641    pub(crate) mod chip_specific {
642        use super::*;
643        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
644        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty();
645        #[inline]
646        pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool {
647            false
648        }
649    }
650}
651
652#[cfg(feature = "rt")]
653mod rt {
654    use super::{vectored::*, *};
655
656    #[unsafe(no_mangle)]
657    #[ram]
658    unsafe fn __level_1_interrupt(save_frame: &mut Context) {
659        unsafe {
660            handle_interrupts::<1>(save_frame);
661        }
662    }
663
664    #[unsafe(no_mangle)]
665    #[ram]
666    unsafe fn __level_2_interrupt(save_frame: &mut Context) {
667        unsafe {
668            handle_interrupts::<2>(save_frame);
669        }
670    }
671
672    #[unsafe(no_mangle)]
673    #[ram]
674    unsafe fn __level_3_interrupt(save_frame: &mut Context) {
675        unsafe {
676            handle_interrupts::<3>(save_frame);
677        }
678    }
679
680    #[inline(always)]
681    unsafe fn handle_interrupts<const LEVEL: u32>(save_frame: &mut Context) {
682        let core = Cpu::current();
683
684        let cpu_interrupt_mask =
685            interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[LEVEL as usize];
686
687        if cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL != 0 {
688            // Let's handle CPU-internal interrupts (NMI, Timer, Software, Profiling).
689            // These are rarely used by the HAL.
690
691            // Mask the relevant bits
692            let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL;
693
694            // Pick one
695            let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
696
697            // If the interrupt is edge triggered, we need to clear the request on the CPU's
698            // side.
699            if ((1 << cpu_interrupt_nr) & CPU_INTERRUPT_EDGE) != 0 {
700                unsafe {
701                    interrupt::clear(1 << cpu_interrupt_nr);
702                }
703            }
704
705            if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) {
706                unsafe { handler(save_frame) };
707            }
708        } else {
709            let status = if !cfg!(esp32s3) && (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
710                // Next, handle edge triggered peripheral interrupts. Note that on the S3 all
711                // peripheral interrupts are level-triggered.
712
713                // If the interrupt is edge triggered, we need to clear the
714                // request on the CPU's side
715                unsafe { interrupt::clear(cpu_interrupt_mask & CPU_INTERRUPT_EDGE) };
716
717                // For edge interrupts we cannot rely on the peripherals' interrupt status
718                // registers, therefore call all registered handlers for current level.
719                chip_specific::INTERRUPT_EDGE
720            } else {
721                // Finally, check level-triggered peripheral sources.
722                // These interrupts are cleared by the peripheral.
723                status(core)
724            };
725
726            let configured_interrupts = configured_interrupts(core, status, LEVEL);
727            for interrupt_nr in configured_interrupts.iterator() {
728                let handler = unsafe { pac::__INTERRUPTS[interrupt_nr as usize]._handler };
729                let handler: fn(&mut Context) = unsafe {
730                    core::mem::transmute::<unsafe extern "C" fn(), fn(&mut Context)>(handler)
731                };
732                handler(save_frame);
733            }
734        }
735    }
736
737    #[inline]
738    pub(crate) fn cpu_interrupt_nr_to_cpu_interrupt_handler(
739        number: u32,
740    ) -> Option<unsafe extern "C" fn(save_frame: &mut Context)> {
741        use xtensa_lx_rt::*;
742        // we're fortunate that all esp variants use the same CPU interrupt layout
743        Some(match number {
744            6 => Timer0,
745            7 => Software0,
746            11 => Profiling,
747            14 => NMI,
748            15 => Timer1,
749            16 => Timer2,
750            29 => Software1,
751            _ => return None,
752        })
753    }
754
755    // Raw handlers for CPU interrupts, assembly only.
756    unsafe extern "C" {
757        fn level4_interrupt(save_frame: &mut Context);
758        fn level5_interrupt(save_frame: &mut Context);
759        fn level6_interrupt(save_frame: &mut Context);
760        fn level7_interrupt(save_frame: &mut Context);
761    }
762
763    #[unsafe(no_mangle)]
764    #[unsafe(link_section = ".rwtext")]
765    unsafe fn __level_4_interrupt(save_frame: &mut Context) {
766        unsafe { level4_interrupt(save_frame) }
767    }
768
769    #[unsafe(no_mangle)]
770    #[unsafe(link_section = ".rwtext")]
771    unsafe fn __level_5_interrupt(save_frame: &mut Context) {
772        unsafe { level5_interrupt(save_frame) }
773    }
774
775    #[unsafe(no_mangle)]
776    #[unsafe(link_section = ".rwtext")]
777    unsafe fn __level_6_interrupt(save_frame: &mut Context) {
778        unsafe { level6_interrupt(save_frame) }
779    }
780
781    #[unsafe(no_mangle)]
782    #[unsafe(link_section = ".rwtext")]
783    unsafe fn __level_7_interrupt(save_frame: &mut Context) {
784        unsafe { level7_interrupt(save_frame) }
785    }
786}