1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::pac::Interrupt;
use cortex_m::peripheral::NVIC;
use cortex_m::peripheral::SCB;
pub trait ScbInit {
fn init(self) -> Scb;
}
pub struct Scb {
pub(crate) scb: SCB,
}
impl ScbInit for SCB {
fn init(self) -> Scb {
Scb { scb: self }
}
}
pub trait NvicInit {
fn init(self) -> Nvic;
}
pub struct Nvic {
pub(crate) nvic: NVIC,
}
impl NvicInit for NVIC {
fn init(self) -> Nvic {
Nvic { nvic: self }
}
}
const SCB_AIRCR_VECTKEY_MASK: u32 = 0xFFFF << 16;
const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16;
const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x7 << 8;
// const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2;
impl Scb {
/// It's best to use Group4.
pub fn set_priority_grouping(&mut self, grouping: PriorityGrouping) {
let mask = !(SCB_AIRCR_VECTKEY_MASK | SCB_AIRCR_PRIGROUP_MASK);
let grouping: u32 = grouping.into();
cortex_m::asm::dsb();
unsafe {
self.scb
.aircr
.modify(|r| (r & mask) | SCB_AIRCR_VECTKEY | grouping)
};
cortex_m::asm::dsb();
}
pub fn get_priority_grouping(&self) -> PriorityGrouping {
self.scb.aircr.read().into()
}
}
impl Nvic {
/// # Parameters
/// - `it`: interrupt line
/// - `priority`: includes 0 ~ 15, The smaller the number, the higher the priority.
/// It combines preemption and sub priority based on the grouping.
/// - `disable`: It is recommended to disable the interrupt, in case it gets activated before you're ready.
/// It will be enabled automatically once you set the interrupt callback.
/// If you set it to `false`, the enable state will not change.
pub fn set_priority(&mut self, it: Interrupt, priority: u8, disable: bool) {
if disable {
NVIC::mask(it);
}
unsafe {
// only use the highest 4 bits
self.nvic.set_priority(it, priority << 4);
}
}
/// Enable or disable a interrupt.
pub fn enable(&mut self, it: Interrupt, en: bool) {
if en {
unsafe {
NVIC::unmask(it);
}
} else {
NVIC::mask(it);
}
}
}
pub enum PriorityGrouping {
/// 0 bits for preemption priority
/// 4 bits for sub priority
Group0,
/// 1 bits for preemption priority
/// 3 bits for sub priority
Group1,
/// 2 bits for preemption priority
/// 2 bits for sub priority
Group2,
/// 3 bits for preemption priority
/// 1 bits for sub priority
Group3,
/// Default used: 4 bits for preemption priority
/// 0 bits for sub priority
Group4,
Unknown(u8),
}
impl From<PriorityGrouping> for u32 {
fn from(value: PriorityGrouping) -> Self {
match value {
PriorityGrouping::Group0 => 7 << 8,
PriorityGrouping::Group1 => 6 << 8,
PriorityGrouping::Group2 => 5 << 8,
PriorityGrouping::Group3 => 4 << 8,
PriorityGrouping::Group4 => 3 << 8,
PriorityGrouping::Unknown(v) => ((v as u32) << 8) & SCB_AIRCR_PRIGROUP_MASK,
}
}
}
impl From<u32> for PriorityGrouping {
fn from(value: u32) -> Self {
match (value & SCB_AIRCR_PRIGROUP_MASK) >> 8 {
7 => Self::Group0,
6 => Self::Group1,
5 => Self::Group2,
4 => Self::Group3,
3 => Self::Group4,
v => PriorityGrouping::Unknown(v as u8),
}
}
}