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