diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index c8f82e6eb2a77645a0fc761ded052a6bbed833f8..74c6625ce75caf457ec9f089167512904f702df2 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -22,8 +22,34 @@ pub struct RegisterBlock {
     /// Interrupt Active Bit
     pub iabr: [RO<u32>; 16],
     reserved4: [u32; 48],
+
+    #[cfg(not(armv6m))]
     /// Interrupt Priority
+    ///
+    /// On ARMv7-M, 124 word-sized registers are available. Each of those
+    /// contains of 4 interrupt priorities of 8 byte each.The architecture
+    /// specifically allows accessing those along byte boundaries, so they are
+    /// represented as 496 byte-sized registers, for convenience, and to allow
+    /// atomic priority updates.
+    ///
+    /// On ARMv6-M, the registers must only be accessed along word boundaries,
+    /// so convenient byte-sized representation wouldn't work on that
+    /// architecture.
     pub ipr: [RW<u8>; 496],
+
+    #[cfg(armv6m)]
+    /// Interrupt Priority
+    ///
+    /// On ARMv7-M, 124 word-sized registers are available. Each of those
+    /// contains of 4 interrupt priorities of 8 byte each.The architecture
+    /// specifically allows accessing those along byte boundaries, so they are
+    /// represented as 496 byte-sized registers, for convenience, and to allow
+    /// atomic priority updates.
+    ///
+    /// On ARMv6-M, the registers must only be accessed along word boundaries,
+    /// so convenient byte-sized representation wouldn't work on that
+    /// architecture.
+    pub ipr: [RW<u32>; 8],
 }
 
 impl RegisterBlock {
@@ -66,9 +92,18 @@ impl RegisterBlock {
     where
         I: Nr,
     {
-        let nr = interrupt.nr();
-
-        self.ipr[usize::from(nr)].read()
+        #[cfg(not(armv6m))]
+        {
+            let nr = interrupt.nr();
+            self.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;
+            prio as u8
+        }
     }
 
     /// Is `interrupt` active or pre-empted and stacked
@@ -118,12 +153,40 @@ impl RegisterBlock {
     ///
     /// NOTE See `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)
     where
         I: Nr,
     {
-        let nr = interrupt.nr();
+        #[cfg(not(armv6m))]
+        {
+            let nr = interrupt.nr();
+            self.ipr[usize::from(nr)].write(prio)
+        }
+
+        #[cfg(armv6m)]
+        {
+            self.ipr[Self::ipr_index(&interrupt)].modify(|value| {
+                let mask = 0x000000ff << Self::ipr_shift(&interrupt);
+                let prio = u32::from(prio) << Self::ipr_shift(&interrupt);
+
+                (value & !mask) | prio
+            })
+        }
+    }
+
+    #[cfg(armv6m)]
+    fn ipr_index<I>(interrupt: &I) -> usize where I: Nr {
+        usize::from(interrupt.nr()) / 4
+    }
 
-        self.ipr[usize::from(nr)].write(prio)
+    #[cfg(armv6m)]
+    fn ipr_shift<I>(interrupt: &I) -> usize where I: Nr {
+        (usize::from(interrupt.nr()) % 4) * 8
     }
 }