diff options
author | 2020-07-22 07:12:25 +0000 | |
---|---|---|
committer | 2020-07-22 07:12:25 +0000 | |
commit | 9dee813277e200f431d0f63522fafe327cdb5034 (patch) | |
tree | c5c70526f9d7a84db4352ad9f423c49a00c8d5fb | |
parent | 498a7a12529bc652727afa5768f4bd5357991401 (diff) | |
parent | a83e5f342711ad9436b95623b6326e58350160ab (diff) | |
download | cortex-m-9dee813277e200f431d0f63522fafe327cdb5034.tar.gz cortex-m-9dee813277e200f431d0f63522fafe327cdb5034.tar.zst cortex-m-9dee813277e200f431d0f63522fafe327cdb5034.zip |
Merge #241
241: Add new InterruptNumber trait r=therealprof a=adamgreig
This is a first go at the new trait needed for https://github.com/rust-embedded/svd2rust/pull/455 since we removed `Nr` from bare-metal.
In this case I've written it as `unsafe trait InterruptNumber: Into<u16>` rather than providing a conversion method inside the trait; I think this is neat and idiomatic but please correct me if there's a reason to not do it like this.
[Here's](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4f2f8b9604b5a62298f9907780d844c7) a playground link showing an example implementation.
Co-authored-by: Adam Greig <adam@adamgreig.com>
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | src/interrupt.rs | 23 | ||||
-rw-r--r-- | src/peripheral/nvic.rs | 64 |
3 files changed, 58 insertions, 34 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 274eb80..a58686f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/interrupt.rs b/src/interrupt.rs index 4d5ef0f..c5da48d 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -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] diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs index 6627e60..a2f85f4 100644 --- a/src/peripheral/nvic.rs +++ b/src/peripheral/nvic.rs @@ -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 @@ -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)); @@ -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)) } } @@ -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)) } @@ -127,11 +127,11 @@ 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() } } @@ -139,8 +139,8 @@ impl NVIC { #[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 } } @@ -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 @@ -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 @@ -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 @@ -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)) } @@ -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 }) @@ -235,9 +235,9 @@ 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)) } @@ -245,19 +245,19 @@ impl NVIC { #[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 } } |