Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new InterruptNumber trait #241

Merged
merged 2 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- New `InterruptNumber` trait is now required on interrupt arguments to the
various NVIC functions, replacing the previous use of `Nr` from bare-metal.

## [v0.6.2] - 2020-01-12

### Added
Expand Down
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
}
}