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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! System configuration: the registers that wire peripherals to each other
//! rather than to the outside world.
//!
//! Covers the boot mode, the interrupt latency, the SRAM parity error flag, the
//! `PA11`/`PA12` remap of packages below 32 pins and `EXTISS`, the latter
//! through [`ExtiLine::source`](crate::exti::ExtiLine::source).
#[cfg(not(pads_ge_lqfp32))]
use crate::gpio::{Active, Input, Pin};
use crate::pac;
use crate::rcu::Rcu;
/// The memory the chip booted from (`BOOT_MODE`).
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BootMode {
/// Main flash: the application.
MainFlash,
/// System flash memory: the factory bootloader.
SystemFlash,
/// Embedded SRAM.
Sram,
}
/// Owns the SYSCFG registers.
pub struct Syscfg {
syscfg: pac::Syscfg,
}
impl Syscfg {
/// Returns the peripheral. The clock stays on, since `CFGCMPEN` also feeds
/// the comparator.
pub fn release(self) -> pac::Syscfg {
self.syscfg
}
/// Returns the memory the chip booted from, as latched at the last reset.
pub fn boot_mode(&self) -> BootMode {
match self.syscfg.cfg0().read().boot_mode().bits() {
0b00 | 0b10 => BootMode::MainFlash,
0b01 => BootMode::SystemFlash,
0b11 => BootMode::Sram,
_ => unreachable!(),
}
}
/// Holds interrupt entry back to no sooner than `latency + 1` cycles of
/// `hclk` after the interrupt pends. A value above the worst natural latency
/// makes entry take the same time whatever the core was executing; `0`, the
/// reset value, enters as early as possible.
pub fn set_irq_latency(&mut self, latency: u8) {
// SAFETY: the field is eight bits wide, so every `u8` is a latency.
self.syscfg
.cpu_irq_lat()
.modify(|_, w| unsafe { w.irq_latency().bits(latency) });
}
/// Whether an SRAM parity error has been caught (`SRAM_PCEF`). Raised only
/// while the check is on, see
/// [`OptionBytes::sram_parity`](crate::fmc::OptionBytes::sram_parity).
pub fn sram_pcef(&self) -> bool {
self.syscfg.cfg2().read().sram_pcef().is_error()
}
/// Clears `SRAM_PCEF`.
pub fn clear_sram_pcef(&mut self) {
self.syscfg.cfg2().modify(|_, w| w.sram_pcef().clear());
}
/// Points EXTI line `line` at the port encoded by `code`.
///
/// # Panics
///
/// If `line` is above 15 — the lines above that have no source to select.
pub(crate) fn set_extiss(&mut self, line: u8, code: u8) {
match line {
// SAFETY: `code` is an `ExtiPin::SS_CODE`, one of the port codes this
// field takes.
l @ 0..=3 => self.syscfg.extiss0().modify(|_, w| unsafe {
match l {
0 => w.exti0_ss().bits(code),
1 => w.exti1_ss().bits(code),
2 => w.exti2_ss().bits(code),
_ => w.exti3_ss().bits(code),
}
}),
// SAFETY: as above.
l @ 4..=7 => self.syscfg.extiss1().modify(|_, w| unsafe {
match l {
4 => w.exti4_ss().bits(code),
5 => w.exti5_ss().bits(code),
6 => w.exti6_ss().bits(code),
_ => w.exti7_ss().bits(code),
}
}),
// SAFETY: as above.
l @ 8..=11 => self.syscfg.extiss2().modify(|_, w| unsafe {
match l {
8 => w.exti8_ss().bits(code),
9 => w.exti9_ss().bits(code),
10 => w.exti10_ss().bits(code),
_ => w.exti11_ss().bits(code),
}
}),
// SAFETY: as above.
l @ 12..=15 => self.syscfg.extiss3().modify(|_, w| unsafe {
match l {
12 => w.exti12_ss().bits(code),
13 => w.exti13_ss().bits(code),
14 => w.exti14_ss().bits(code),
_ => w.exti15_ss().bits(code),
}
}),
_ => unreachable!(),
}
}
}
#[cfg(not(pads_ge_lqfp32))]
impl Syscfg {
/// Hands the `PA9`/`PA10` pads over to `PA11`/`PA12`, which come back as
/// inputs.
///
/// Packages below 32 pins bond one pair or the other on the same two pads,
/// `PA9`/`PA10` after reset.
pub fn remap_pa11_pa12<M9: Active, M10: Active>(
&mut self,
_pa9: Pin<'A', 9, M9>,
_pa10: Pin<'A', 10, M10>,
) -> (Pin<'A', 11, Input>, Pin<'A', 12, Input>) {
let pins = (Pin::take_as_input(), Pin::take_as_input());
self.syscfg
.cfg0()
.modify(|_, w| w.pa11_pa12_rmp().set_bit());
pins
}
/// Gives the pads back to `PA9`/`PA10`, which come back as inputs.
pub fn unmap_pa11_pa12<M11: Active, M12: Active>(
&mut self,
_pa11: Pin<'A', 11, M11>,
_pa12: Pin<'A', 12, M12>,
) -> (Pin<'A', 9, Input>, Pin<'A', 10, Input>) {
let pins = (Pin::take_as_input(), Pin::take_as_input());
self.syscfg
.cfg0()
.modify(|_, w| w.pa11_pa12_rmp().clear_bit());
pins
}
}
/// Takes the raw peripheral into [`Syscfg`].
pub trait SyscfgExt {
/// Switches the SYSCFG clock on and hands back the owning type.
///
/// The clock bit is shared with the comparator, so CMP is clocked too; see
/// [`Rcu::enable_cfgcmp`].
fn constrain(self, rcu: &mut Rcu) -> Syscfg;
}
impl SyscfgExt for pac::Syscfg {
fn constrain(self, rcu: &mut Rcu) -> Syscfg {
rcu.enable_cfgcmp();
Syscfg { syscfg: self }
}
}