aboutsummaryrefslogtreecommitdiff
path: root/src/peripheral/nvic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/peripheral/nvic.rs')
-rw-r--r--src/peripheral/nvic.rs67
1 files changed, 38 insertions, 29 deletions
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 74c6625..8c55a87 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -2,6 +2,7 @@
use volatile_register::{RO, RW};
+use peripheral::NVIC;
use interrupt::Nr;
/// Register block
@@ -52,9 +53,9 @@ pub struct RegisterBlock {
pub ipr: [RW<u32>; 8],
}
-impl RegisterBlock {
+impl NVIC {
/// Clears `interrupt`'s pending state
- pub fn clear_pending<I>(&self, interrupt: I)
+ pub fn clear_pending<I>(&mut self, interrupt: I)
where
I: Nr,
{
@@ -64,7 +65,7 @@ impl RegisterBlock {
}
/// Disables `interrupt`
- pub fn disable<I>(&self, interrupt: I)
+ pub fn disable<I>(&mut self, interrupt: I)
where
I: Nr,
{
@@ -74,7 +75,7 @@ impl RegisterBlock {
}
/// Enables `interrupt`
- pub fn enable<I>(&self, interrupt: I)
+ pub fn enable<I>(&mut self, interrupt: I)
where
I: Nr,
{
@@ -83,64 +84,69 @@ impl RegisterBlock {
unsafe { self.iser[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
- /// Gets the "priority" of `interrupt`
+ /// Returns the NVIC priority of `interrupt`
///
- /// NOTE NVIC encodes priority in the highest bits of a byte so values like
- /// `1` and `2` have the same priority. Also for NVIC priorities, a lower
- /// value (e.g. `16`) has higher priority than a larger value (e.g. `32`).
- pub fn get_priority<I>(&self, interrupt: I) -> u8
+ /// *NOTE* NVIC encodes priority in the highest bits of a byte so values like `1` and `2` map
+ /// the same priority. Also for NVIC priorities, a lower value (e.g. `16`) has higher priority
+ /// (urgency) than a larger value (e.g. `32`).
+ pub fn get_priority<I>(interrupt: I) -> u8
where
I: Nr,
{
#[cfg(not(armv6m))]
{
let nr = interrupt.nr();
- self.ipr[usize::from(nr)].read()
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ipr[usize::from(nr)].read() }
}
#[cfg(armv6m)]
{
- let ipr_n = self.ipr[Self::ipr_index(&interrupt)].read();
- let prio = (ipr_n >> Self::ipr_shift(&interrupt)) & 0x000000ff;
+ // NOTE(unsafe) atomic read with no side effects
+ let ipr_n = (*Self::ptr()).ipr[Self::ipr_index(&interrupt)].read();
+ let prio = (ipr_n >> Self::ipr_shift(&interrupt)) & 0x000000ff;
prio as u8
}
}
/// Is `interrupt` active or pre-empted and stacked
- pub fn is_active<I>(&self, interrupt: I) -> bool
+ pub fn is_active<I>(interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
- (self.iabr[usize::from(nr / 32)].read() & mask) == mask
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { ((*Self::ptr()).iabr[usize::from(nr / 32)].read() & mask) == mask }
}
/// Checks if `interrupt` is enabled
- pub fn is_enabled<I>(&self, interrupt: I) -> bool
+ pub fn is_enabled<I>(interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
- (self.iser[usize::from(nr / 32)].read() & mask) == mask
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { ((*Self::ptr()).iser[usize::from(nr / 32)].read() & mask) == mask }
}
/// Checks if `interrupt` is pending
- pub fn is_pending<I>(&self, interrupt: I) -> bool
+ pub fn is_pending<I>(interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
- (self.ispr[usize::from(nr / 32)].read() & mask) == mask
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { ((*Self::ptr()).ispr[usize::from(nr / 32)].read() & mask) == mask }
}
/// Forces `interrupt` into pending state
- pub fn set_pending<I>(&self, interrupt: I)
+ pub fn set_pending<I>(&mut self, interrupt: I)
where
I: Nr,
{
@@ -151,15 +157,12 @@ impl RegisterBlock {
/// Sets the "priority" of `interrupt` to `prio`
///
- /// NOTE See `get_priority` method for an explanation of how NVIC priorities
- /// work.
+ /// *NOTE* See [`get_priority`](struct.NVIC.html#method.get_priority) method for an explanation
+ /// of how NVIC priorities work.
///
- /// On ARMv6-M, updating an interrupt priority requires a read-modify-write
- /// operation, which is not atomic. This is inherently racy, so please
- /// ensure proper access to this method.
- ///
- /// On ARMv7-M, this method is atomic.
- pub unsafe fn set_priority<I>(&self, interrupt: I, prio: u8)
+ /// On ARMv6-M, updating an interrupt priority requires a read-modify-write operation. On
+ /// ARMv7-M, the operation is performed in a single atomic write operation.
+ pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
I: Nr,
{
@@ -181,12 +184,18 @@ impl RegisterBlock {
}
#[cfg(armv6m)]
- fn ipr_index<I>(interrupt: &I) -> usize where I: Nr {
+ fn ipr_index<I>(interrupt: &I) -> usize
+ where
+ I: Nr,
+ {
usize::from(interrupt.nr()) / 4
}
#[cfg(armv6m)]
- fn ipr_shift<I>(interrupt: &I) -> usize where I: Nr {
+ fn ipr_shift<I>(interrupt: &I) -> usize
+ where
+ I: Nr,
+ {
(usize::from(interrupt.nr()) % 4) * 8
}
}