Skip to content
Snippets Groups Projects
Commit d952f0ca authored by Hanno Braun's avatar Hanno Braun
Browse files

Fix `IPR` representation on ARMv6-M

On ARMv6-M, anything but world-aligned access to the IPR registers will
lead to unpredictable results.

Fixes #61.
parent 03779e5a
Branches
Tags
No related merge requests found
...@@ -22,8 +22,34 @@ pub struct RegisterBlock { ...@@ -22,8 +22,34 @@ pub struct RegisterBlock {
/// Interrupt Active Bit /// Interrupt Active Bit
pub iabr: [RO<u32>; 16], pub iabr: [RO<u32>; 16],
reserved4: [u32; 48], reserved4: [u32; 48],
#[cfg(not(armv6m))]
/// Interrupt Priority /// 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], 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 { impl RegisterBlock {
...@@ -65,12 +91,21 @@ impl RegisterBlock { ...@@ -65,12 +91,21 @@ impl RegisterBlock {
pub fn get_priority<I>(&self, interrupt: I) -> u8 pub fn get_priority<I>(&self, interrupt: I) -> u8
where where
I: Nr, I: Nr,
{
#[cfg(not(armv6m))]
{ {
let nr = interrupt.nr(); let nr = interrupt.nr();
self.ipr[usize::from(nr)].read() 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 /// Is `interrupt` active or pre-empted and stacked
pub fn is_active<I>(&self, interrupt: I) -> bool pub fn is_active<I>(&self, interrupt: I) -> bool
where where
...@@ -118,12 +153,40 @@ impl RegisterBlock { ...@@ -118,12 +153,40 @@ impl RegisterBlock {
/// ///
/// NOTE See `get_priority` method for an explanation of how NVIC priorities /// NOTE See `get_priority` method for an explanation of how NVIC priorities
/// work. /// 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) pub unsafe fn set_priority<I>(&self, interrupt: I, prio: u8)
where where
I: Nr, I: Nr,
{
#[cfg(not(armv6m))]
{ {
let nr = interrupt.nr(); let nr = interrupt.nr();
self.ipr[usize::from(nr)].write(prio) 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
}
#[cfg(armv6m)]
fn ipr_shift<I>(interrupt: &I) -> usize where I: Nr {
(usize::from(interrupt.nr()) % 4) * 8
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment