aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2018-10-24 11:40:14 +0200
committerGravatar Jorge Aparicio <jorge@japaric.io> 2018-10-24 11:40:14 +0200
commit66e1d707223697fa4c31006899d7e54fd30f5a39 (patch)
tree673b44cdec8688ec266ca06323d87facc133587e /src
parente3b7357002f0fa739253c78623f825e0e8a7f1ab (diff)
downloadcortex-m-66e1d707223697fa4c31006899d7e54fd30f5a39.tar.gz
cortex-m-66e1d707223697fa4c31006899d7e54fd30f5a39.tar.zst
cortex-m-66e1d707223697fa4c31006899d7e54fd30f5a39.zip
add high level API to set priority of system handlers
Diffstat (limited to 'src')
-rw-r--r--src/peripheral/nvic.rs5
-rw-r--r--src/peripheral/scb.rs113
2 files changed, 118 insertions, 0 deletions
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 1a6a027..1005799 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -177,6 +177,11 @@ impl NVIC {
///
/// 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.
+ ///
+ /// # Unsafety
+ ///
+ /// Changing priority levels can break priority-based critical sections (see
+ /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
I: Nr,
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
index e773c9c..5593792 100644
--- a/src/peripheral/scb.rs
+++ b/src/peripheral/scb.rs
@@ -669,3 +669,116 @@ impl SCB {
}
}
}
+
+/// System handlers, exceptions with configurable priority
+#[allow(non_camel_case_types)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum SystemHandler {
+ // NonMaskableInt, // priority is fixed
+ // HardFault, // priority is fixed
+ /// Memory management interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ MemoryManagement,
+
+ /// Bus fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ BusFault,
+
+ /// Usage fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ UsageFault,
+
+ /// Secure fault interrupt (only on ARMv8-M)
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ SecureFault,
+
+ /// SV call interrupt
+ SVCall,
+
+ // #[cfg(not(armv6m))]
+ // DebugMonitor, // unclear whether this has configurable priority
+ /// Pend SV interrupt
+ PendSV,
+
+ /// System Tick interrupt
+ SysTick,
+
+ // Make this enum extensible
+ #[doc(hidden)]
+ __DO_NOT_MATCH_AGAINST_THIS_VARIANT__,
+}
+
+impl SystemHandler {
+ fn index(&self) -> u8 {
+ match *self {
+ #[cfg(not(armv6m))]
+ SystemHandler::MemoryManagement => 4,
+ #[cfg(not(armv6m))]
+ SystemHandler::BusFault => 5,
+ #[cfg(not(armv6m))]
+ SystemHandler::UsageFault => 6,
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ SystemHandler::SecureFault => 7,
+ SystemHandler::SVCall => 11,
+ SystemHandler::PendSV => 14,
+ SystemHandler::SysTick => 15,
+ SystemHandler::__DO_NOT_MATCH_AGAINST_THIS_VARIANT__ => unreachable!(),
+ }
+ }
+}
+
+impl SCB {
+ /// Returns the hardware priority of `system_handler`
+ ///
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
+ pub fn get_priority(system_handler: SystemHandler) -> u8 {
+ let index = system_handler.index();
+
+ #[cfg(not(armv6m))]
+ {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).shpr[usize::from(index - 4)].read() }
+ }
+
+ #[cfg(armv6m)]
+ {
+ // NOTE(unsafe) atomic read with no side effects
+ let shpr = unsafe { (*Self::ptr()).shpr[usize::from((index - 8) / 4)].read() };
+ let prio = (shpr >> (index % 4)) & 0x000000ff;
+ prio as u8
+ }
+ }
+
+ /// Sets the hardware priority of `system_handler` to `prio`
+ ///
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
+ ///
+ /// On ARMv6-M, updating a system handler priority requires a read-modify-write operation. On
+ /// ARMv7-M, the operation is performed in a single, atomic write operation.
+ ///
+ /// # Unsafety
+ ///
+ /// Changing priority levels can break priority-based critical sections (see
+ /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ pub unsafe fn set_priority(&mut self, system_handler: SystemHandler, prio: u8) {
+ let index = system_handler.index();
+
+ #[cfg(not(armv6m))]
+ {
+ self.shpr[usize::from(index - 4)].write(prio)
+ }
+
+ #[cfg(armv6m)]
+ {
+ self.shpr[usize::from((index - 8) / 4)].modify(|value| {
+ let shift = index % 4;
+ let mask = 0x000000ff << shift;
+ let prio = u32::from(prio) << shift;
+
+ (value & !mask) | prio
+ });
+ }
+ }
+}