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