cortexm/
nvic.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Cortex-M Nested Vectored Interrupt Controller (NVIC)
6//!
7//! Most NVIC configuration is in the NVIC registers:
8//! <https://developer.arm.com/docs/100165/0201/nested-vectored-interrupt-controller/nvic-programmers-model/table-of-nvic-registers>
9//!
10//! Also part of the NVIC conceptually is the ICTR, which in older versions of
11//! the ARM ARM was listed in the "Summary of system control and ID registers
12//! not in the SCB" and newer ARM ARMs just file it in its own little private
13//! sub-section with the NVIC documentation. Seems a configuration register
14//! without a home, so we include it in the NVIC files as it's conceptually here.
15//! <https://developer.arm.com/docs/ddi0337/latest/nested-vectored-interrupt-controller/nvic-programmers-model/interrupt-controller-type-register-ictr>
16
17use kernel::utilities::registers::interfaces::{Readable, Writeable};
18use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
19use kernel::utilities::StaticRef;
20
21/// Generates the (u128, u128) tuple used for the NVIC's mask functions
22/// `next_pending_with_mask` and `next_pending_with_mask`.
23///
24/// ```rust,ignore
25/// if let Some(interrupt) =
26///     cortexm0p::nvic::next_pending_with_mask(interrupt_mask!(interrupts::SIO_IRQ_PROC1))
27/// {
28///     // ...
29/// }
30/// ```
31#[macro_export]
32macro_rules! interrupt_mask {
33    ($($interrupt: expr),+) => {{
34        let mut high_interrupt: u128 = 0;
35        let mut low_interrupt: u128 = 0;
36        $(
37            // Validate that the interrupt index is within the high and low
38            // interrupt range.
39            const{ assert!($interrupt < 256); }
40            const{ assert!($interrupt >= 0); }
41
42            if ($interrupt < 128) {
43                low_interrupt |= (1u128 << $interrupt)
44            }
45            else
46            {
47                high_interrupt |= (1u128 << ($interrupt-128))
48            }
49        );+
50        (high_interrupt, low_interrupt)
51    }};
52}
53
54register_structs! {
55    /// NVIC Registers.
56    ///
57    /// Note this generic interface exposes all possible NVICs. Most cores will
58    /// not implement all NVIC_XXXX registers. If you need to find the number
59    /// of NVICs dynamically, consult `ICTR.INTLINESNUM`.
60    NvicRegisters {
61        (0x000 => _reserved0),
62
63        /// Interrupt Controller Type Register
64        (0x004 => ictr: ReadOnly<u32, InterruptControllerType::Register>),
65
66        (0x008 => _reserved1),
67
68        /// Interrupt Set-Enable Registers
69        (0x100 => iser: [ReadWrite<u32, NvicSetClear::Register>; 32]),
70
71        /// Interrupt Clear-Enable Registers
72        (0x180 => icer: [ReadWrite<u32, NvicSetClear::Register>; 32]),
73
74        /// Interrupt Set-Pending Registers
75        (0x200 => ispr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
76
77        /// Interrupt Clear-Pending Registers
78        (0x280 => icpr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
79
80        /// Interrupt Active Bit Registers
81        (0x300 => iabr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
82
83        (0x380 => _reserved2),
84
85        /// Interrupt Priority Registers
86        (0x400 => ipr: [ReadWrite<u32, NvicInterruptPriority::Register>; 252]),
87
88        (0x7f0 => @END),
89    }
90}
91
92register_bitfields![u32,
93    InterruptControllerType [
94        /// Total number of interrupt lines in groups of 32
95        INTLINESNUM     OFFSET(0)   NUMBITS(4)
96    ],
97
98    NvicSetClear [
99        /// For register NVIC_XXXXn, access interrupt (m+(32*n)).
100        ///  - m takes the values from 31 to 0, except for NVIC_XXXX15, where:
101        ///     - m takes the values from 15 to 0
102        ///     - register bits[31:16] are reserved, RAZ/WI
103        BITS            OFFSET(0)   NUMBITS(32)
104    ],
105
106    NvicInterruptPriority [
107        /// For register NVIC_IPRn, priority of interrupt number 4n+3.
108        PRI_N3          OFFSET(24)  NUMBITS(8),
109
110        /// For register NVIC_IPRn, priority of interrupt number 4n+2.
111        PRI_N2          OFFSET(16)  NUMBITS(8),
112
113        /// For register NVIC_IPRn, priority of interrupt number 4n+1.
114        PRI_N1          OFFSET(8)   NUMBITS(8),
115
116        /// For register NVIC_IPRn, priority of interrupt number 4n.
117        PRI_N0          OFFSET(0)   NUMBITS(8)
118    ]
119];
120
121/// The NVIC peripheral in MMIO space.
122const NVIC: StaticRef<NvicRegisters> =
123    unsafe { StaticRef::new(0xe000e000 as *const NvicRegisters) };
124
125/// Number of valid NVIC_XXXX registers. Note this is a ceiling on the number
126/// of available interrupts (as this is the number of banks of 32), but the
127/// actual number may be less. See NVIC and ICTR documentation for more detail.
128fn number_of_nvic_registers() -> usize {
129    (NVIC.ictr.read(InterruptControllerType::INTLINESNUM) + 1) as usize
130}
131
132/// Clear all pending interrupts
133pub unsafe fn clear_all_pending() {
134    for icpr in NVIC.icpr.iter().take(number_of_nvic_registers()) {
135        icpr.set(!0)
136    }
137}
138
139/// Enable all interrupts
140pub unsafe fn enable_all() {
141    for icer in NVIC.iser.iter().take(number_of_nvic_registers()) {
142        icer.set(!0)
143    }
144}
145
146/// Disable all interrupts
147pub unsafe fn disable_all() {
148    for icer in NVIC.icer.iter().take(number_of_nvic_registers()) {
149        icer.set(!0)
150    }
151}
152
153/// Get the index (0-240) the lowest number pending interrupt, or `None` if none
154/// are pending.
155pub unsafe fn next_pending() -> Option<u32> {
156    for (block, ispr) in NVIC
157        .ispr
158        .iter()
159        .take(number_of_nvic_registers())
160        .enumerate()
161    {
162        let ispr = ispr.get();
163
164        // If there are any high bits there is a pending interrupt
165        if ispr != 0 {
166            // trailing_zeros == index of first high bit
167            let bit = ispr.trailing_zeros();
168            return Some(block as u32 * 32 + bit);
169        }
170    }
171    None
172}
173
174/// Get the index (0-240) the lowest number pending interrupt while ignoring the
175/// interrupts that correspond to the bits set in mask, or `None` if none are
176/// pending.
177///
178/// Mask is defined as two `u128` fields,
179///   `mask.0` has the bits corresponding to interrupts from 128 to 240.
180///   `mask.1` has the bits corresponding to interrupts from 0 to 127.
181pub unsafe fn next_pending_with_mask(mask: (u128, u128)) -> Option<u32> {
182    for (block, ispr) in NVIC
183        .ispr
184        .iter()
185        .take(number_of_nvic_registers())
186        .enumerate()
187    {
188        let interrupt_mask = if block < 4 { mask.1 } else { mask.0 };
189        let ispr_masked = ispr.get() & !((interrupt_mask >> (32 * (block % 4))) as u32);
190
191        // If there are any high bits there is a pending interrupt
192        if ispr_masked != 0 {
193            // trailing_zeros == index of first high bit
194            let bit = ispr_masked.trailing_zeros();
195            return Some(block as u32 * 32 + bit);
196        }
197    }
198    None
199}
200
201pub unsafe fn has_pending() -> bool {
202    NVIC.ispr
203        .iter()
204        .take(number_of_nvic_registers())
205        .fold(0, |i, ispr| ispr.get() | i)
206        != 0
207}
208
209/// Returns whether there are any pending interrupt bits set while ignoring
210/// the indices that correspond to the bits set in mask
211///
212/// Mask is defined as two `u128` fields,
213///   `mask.0` has the bits corresponding to interrupts from 128 to 240.
214///   `mask.1` has the bits corresponding to interrupts from 0 to 127.
215pub unsafe fn has_pending_with_mask(mask: (u128, u128)) -> bool {
216    NVIC.ispr
217        .iter()
218        .take(number_of_nvic_registers())
219        .enumerate()
220        .fold(0, |i, (block, ispr)| {
221            let interrupt_mask = if block < 4 { mask.1 } else { mask.0 };
222            (ispr.get() & !((interrupt_mask >> (32 * (block % 4))) as u32)) | i
223        })
224        != 0
225}
226
227/// An opaque wrapper for a single NVIC interrupt.
228///
229/// Hand these out to low-level driver to let them control their own interrupts
230/// but not others.
231pub struct Nvic(u32);
232
233impl Nvic {
234    /// Creates a new `Nvic`.
235    ///
236    /// Marked unsafe because only chip/platform configuration code should be
237    /// able to create these.
238    pub const unsafe fn new(idx: u32) -> Nvic {
239        Nvic(idx)
240    }
241
242    /// Enable the interrupt
243    pub fn enable(&self) {
244        let idx = self.0 as usize;
245
246        NVIC.iser[idx / 32].set(1 << (self.0 & 31));
247    }
248
249    /// Disable the interrupt
250    pub fn disable(&self) {
251        let idx = self.0 as usize;
252
253        NVIC.icer[idx / 32].set(1 << (self.0 & 31));
254    }
255
256    /// Clear pending state
257    pub fn clear_pending(&self) {
258        let idx = self.0 as usize;
259
260        NVIC.icpr[idx / 32].set(1 << (self.0 & 31));
261    }
262}