gd32e2_hal/syscfg.rs
1//! System configuration: the registers that wire peripherals to each other
2//! rather than to the outside world.
3//!
4//! Covers the boot mode, the interrupt latency, the SRAM parity error flag, the
5//! `PA11`/`PA12` remap of packages below 32 pins and `EXTISS`, the latter
6//! through [`ExtiLine::source`](crate::exti::ExtiLine::source).
7
8#[cfg(not(pads_ge_lqfp32))]
9use crate::gpio::{Active, Input, Pin};
10use crate::pac;
11use crate::rcu::Rcu;
12
13/// The memory the chip booted from (`BOOT_MODE`).
14#[derive(Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum BootMode {
17 /// Main flash: the application.
18 MainFlash,
19 /// System flash memory: the factory bootloader.
20 SystemFlash,
21 /// Embedded SRAM.
22 Sram,
23}
24
25/// Owns the SYSCFG registers.
26pub struct Syscfg {
27 syscfg: pac::Syscfg,
28}
29
30impl Syscfg {
31 /// Returns the peripheral. The clock stays on, since `CFGCMPEN` also feeds
32 /// the comparator.
33 pub fn release(self) -> pac::Syscfg {
34 self.syscfg
35 }
36
37 /// Returns the memory the chip booted from, as latched at the last reset.
38 pub fn boot_mode(&self) -> BootMode {
39 match self.syscfg.cfg0().read().boot_mode().bits() {
40 0b00 | 0b10 => BootMode::MainFlash,
41 0b01 => BootMode::SystemFlash,
42 0b11 => BootMode::Sram,
43 _ => unreachable!(),
44 }
45 }
46
47 /// Holds interrupt entry back to no sooner than `latency + 1` cycles of
48 /// `hclk` after the interrupt pends. A value above the worst natural latency
49 /// makes entry take the same time whatever the core was executing; `0`, the
50 /// reset value, enters as early as possible.
51 pub fn set_irq_latency(&mut self, latency: u8) {
52 // SAFETY: the field is eight bits wide, so every `u8` is a latency.
53 self.syscfg
54 .cpu_irq_lat()
55 .modify(|_, w| unsafe { w.irq_latency().bits(latency) });
56 }
57
58 /// Whether an SRAM parity error has been caught (`SRAM_PCEF`). Raised only
59 /// while the check is on, see
60 /// [`OptionBytes::sram_parity`](crate::fmc::OptionBytes::sram_parity).
61 pub fn sram_pcef(&self) -> bool {
62 self.syscfg.cfg2().read().sram_pcef().is_error()
63 }
64 /// Clears `SRAM_PCEF`.
65 pub fn clear_sram_pcef(&mut self) {
66 self.syscfg.cfg2().modify(|_, w| w.sram_pcef().clear());
67 }
68
69 /// Points EXTI line `line` at the port encoded by `code`.
70 ///
71 /// # Panics
72 ///
73 /// If `line` is above 15 — the lines above that have no source to select.
74 pub(crate) fn set_extiss(&mut self, line: u8, code: u8) {
75 match line {
76 // SAFETY: `code` is an `ExtiPin::SS_CODE`, one of the port codes this
77 // field takes.
78 l @ 0..=3 => self.syscfg.extiss0().modify(|_, w| unsafe {
79 match l {
80 0 => w.exti0_ss().bits(code),
81 1 => w.exti1_ss().bits(code),
82 2 => w.exti2_ss().bits(code),
83 _ => w.exti3_ss().bits(code),
84 }
85 }),
86 // SAFETY: as above.
87 l @ 4..=7 => self.syscfg.extiss1().modify(|_, w| unsafe {
88 match l {
89 4 => w.exti4_ss().bits(code),
90 5 => w.exti5_ss().bits(code),
91 6 => w.exti6_ss().bits(code),
92 _ => w.exti7_ss().bits(code),
93 }
94 }),
95 // SAFETY: as above.
96 l @ 8..=11 => self.syscfg.extiss2().modify(|_, w| unsafe {
97 match l {
98 8 => w.exti8_ss().bits(code),
99 9 => w.exti9_ss().bits(code),
100 10 => w.exti10_ss().bits(code),
101 _ => w.exti11_ss().bits(code),
102 }
103 }),
104 // SAFETY: as above.
105 l @ 12..=15 => self.syscfg.extiss3().modify(|_, w| unsafe {
106 match l {
107 12 => w.exti12_ss().bits(code),
108 13 => w.exti13_ss().bits(code),
109 14 => w.exti14_ss().bits(code),
110 _ => w.exti15_ss().bits(code),
111 }
112 }),
113 _ => unreachable!(),
114 }
115 }
116}
117
118#[cfg(not(pads_ge_lqfp32))]
119impl Syscfg {
120 /// Hands the `PA9`/`PA10` pads over to `PA11`/`PA12`, which come back as
121 /// inputs.
122 ///
123 /// Packages below 32 pins bond one pair or the other on the same two pads,
124 /// `PA9`/`PA10` after reset.
125 pub fn remap_pa11_pa12<M9: Active, M10: Active>(
126 &mut self,
127 _pa9: Pin<'A', 9, M9>,
128 _pa10: Pin<'A', 10, M10>,
129 ) -> (Pin<'A', 11, Input>, Pin<'A', 12, Input>) {
130 let pins = (Pin::take_as_input(), Pin::take_as_input());
131 self.syscfg
132 .cfg0()
133 .modify(|_, w| w.pa11_pa12_rmp().set_bit());
134 pins
135 }
136 /// Gives the pads back to `PA9`/`PA10`, which come back as inputs.
137 pub fn unmap_pa11_pa12<M11: Active, M12: Active>(
138 &mut self,
139 _pa11: Pin<'A', 11, M11>,
140 _pa12: Pin<'A', 12, M12>,
141 ) -> (Pin<'A', 9, Input>, Pin<'A', 10, Input>) {
142 let pins = (Pin::take_as_input(), Pin::take_as_input());
143 self.syscfg
144 .cfg0()
145 .modify(|_, w| w.pa11_pa12_rmp().clear_bit());
146 pins
147 }
148}
149
150/// Takes the raw peripheral into [`Syscfg`].
151pub trait SyscfgExt {
152 /// Switches the SYSCFG clock on and hands back the owning type.
153 ///
154 /// The clock bit is shared with the comparator, so CMP is clocked too; see
155 /// [`Rcu::enable_cfgcmp`].
156 fn constrain(self, rcu: &mut Rcu) -> Syscfg;
157}
158
159impl SyscfgExt for pac::Syscfg {
160 fn constrain(self, rcu: &mut Rcu) -> Syscfg {
161 rcu.enable_cfgcmp();
162 Syscfg { syscfg: self }
163 }
164}