Skip to content

Commit

Permalink
Add new InterruptNumber trait
Browse files Browse the repository at this point in the history
  • Loading branch information
adamgreig committed Jul 21, 2020
1 parent 9021bcd commit b5ad45c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 34 deletions.
23 changes: 21 additions & 2 deletions src/interrupt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
//! Interrupts
// use core::sync::atomic::{self, Ordering};
pub use bare_metal::{CriticalSection, Mutex};

pub use bare_metal::{CriticalSection, Mutex, Nr};
/// Trait for enums of external interrupt numbers.
///
/// This trait should be implemented by a peripheral access crate (PAC)
/// on its enum of available external interrupts for a specific device.
/// Each variant must convert to a u16 of its interrupt number,
/// which is its exception number - 16.
///
/// # Safety
///
/// This trait must only be implemented on enums of device interrupts. Each
/// enum variant must represent a distinct value (no duplicates are permitted),
/// and must always return the same value (do not change at runtime).
///
/// These requirements ensure safe nesting of critical sections.
pub unsafe trait InterruptNumber: Copy {
/// Return the interrupt number associated with this variant.
///
/// See trait documentation for safety requirements.
fn number(self) -> u16;
}

/// Disables all interrupts
#[inline]
Expand Down
64 changes: 32 additions & 32 deletions src/peripheral/nvic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use volatile_register::RW;
#[cfg(not(armv6m))]
use volatile_register::{RO, WO};

use crate::interrupt::Nr;
use crate::interrupt::InterruptNumber;
use crate::peripheral::NVIC;

/// Register block
Expand Down Expand Up @@ -86,9 +86,9 @@ impl NVIC {
#[inline]
pub fn request<I>(&mut self, interrupt: I)
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();

unsafe {
self.stir.write(u32::from(nr));
Expand All @@ -99,9 +99,9 @@ impl NVIC {
#[inline]
pub fn mask<I>(interrupt: I)
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();
// NOTE(unsafe) this is a write to a stateless register
unsafe { (*Self::ptr()).icer[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
Expand All @@ -112,9 +112,9 @@ impl NVIC {
#[inline]
pub unsafe fn unmask<I>(interrupt: I)
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();
// NOTE(ptr) this is a write to a stateless register
(*Self::ptr()).iser[usize::from(nr / 32)].write(1 << (nr % 32))
}
Expand All @@ -127,20 +127,20 @@ impl NVIC {
#[inline]
pub fn get_priority<I>(interrupt: I) -> u8
where
I: Nr,
I: InterruptNumber,
{
#[cfg(not(armv6m))]
{
let nr = interrupt.nr();
let nr = interrupt.number();
// NOTE(unsafe) atomic read with no side effects
unsafe { (*Self::ptr()).ipr[usize::from(nr)].read() }
}

#[cfg(armv6m)]
{
// NOTE(unsafe) atomic read with no side effects
let ipr_n = unsafe { (*Self::ptr()).ipr[Self::ipr_index(&interrupt)].read() };
let prio = (ipr_n >> Self::ipr_shift(&interrupt)) & 0x0000_00ff;
let ipr_n = unsafe { (*Self::ptr()).ipr[Self::ipr_index(interrupt)].read() };
let prio = (ipr_n >> Self::ipr_shift(interrupt)) & 0x0000_00ff;
prio as u8
}
}
Expand All @@ -150,9 +150,9 @@ impl NVIC {
#[inline]
pub fn is_active<I>(interrupt: I) -> bool
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();
let mask = 1 << (nr % 32);

// NOTE(unsafe) atomic read with no side effects
Expand All @@ -163,9 +163,9 @@ impl NVIC {
#[inline]
pub fn is_enabled<I>(interrupt: I) -> bool
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();
let mask = 1 << (nr % 32);

// NOTE(unsafe) atomic read with no side effects
Expand All @@ -176,9 +176,9 @@ impl NVIC {
#[inline]
pub fn is_pending<I>(interrupt: I) -> bool
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();
let mask = 1 << (nr % 32);

// NOTE(unsafe) atomic read with no side effects
Expand All @@ -189,9 +189,9 @@ impl NVIC {
#[inline]
pub fn pend<I>(interrupt: I)
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();

// NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
unsafe { (*Self::ptr()).ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
Expand All @@ -212,19 +212,19 @@ impl NVIC {
#[inline]
pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
I: Nr,
I: InterruptNumber,
{
#[cfg(not(armv6m))]
{
let nr = interrupt.nr();
let nr = interrupt.number();
self.ipr[usize::from(nr)].write(prio)
}

#[cfg(armv6m)]
{
self.ipr[Self::ipr_index(&interrupt)].modify(|value| {
let mask = 0x0000_00ff << Self::ipr_shift(&interrupt);
let prio = u32::from(prio) << Self::ipr_shift(&interrupt);
self.ipr[Self::ipr_index(interrupt)].modify(|value| {
let mask = 0x0000_00ff << Self::ipr_shift(interrupt);
let prio = u32::from(prio) << Self::ipr_shift(interrupt);

(value & !mask) | prio
})
Expand All @@ -235,29 +235,29 @@ impl NVIC {
#[inline]
pub fn unpend<I>(interrupt: I)
where
I: Nr,
I: InterruptNumber,
{
let nr = interrupt.nr();
let nr = interrupt.number();

// NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
unsafe { (*Self::ptr()).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
}

#[cfg(armv6m)]
#[inline]
fn ipr_index<I>(interrupt: &I) -> usize
fn ipr_index<I>(interrupt: I) -> usize
where
I: Nr,
I: InterruptNumber,
{
usize::from(interrupt.nr()) / 4
usize::from(interrupt.number()) / 4
}

#[cfg(armv6m)]
#[inline]
fn ipr_shift<I>(interrupt: &I) -> usize
fn ipr_shift<I>(interrupt: I) -> usize
where
I: Nr,
I: InterruptNumber,
{
(usize::from(interrupt.nr()) % 4) * 8
(usize::from(interrupt.number()) % 4) * 8
}
}

0 comments on commit b5ad45c

Please sign in to comment.