stm32f1_hal/
nvic_scb.rs

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