aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rcc/g0.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-01-04 19:25:50 +0100
committerDario Nieuwenhuis <[email protected]>2022-01-04 19:28:15 +0100
commitb06e705a737a7b1d040ab415b4e7ecc71cd79094 (patch)
tree8c4ff244645f561cee4db194253613de949fcdef /embassy-stm32/src/rcc/g0.rs
parentb2a85ee519067d3290e328f9ad047184ff033cd7 (diff)
stm32/rcc: change family-specific code from dirs to single files.
Consistent with how other peripherals handle their versions.
Diffstat (limited to 'embassy-stm32/src/rcc/g0.rs')
-rw-r--r--embassy-stm32/src/rcc/g0.rs234
1 files changed, 234 insertions, 0 deletions
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
new file mode 100644
index 000000000..df11ff36d
--- /dev/null
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -0,0 +1,234 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9
10/// HSI speed
11pub const HSI_FREQ: u32 = 16_000_000;
12
13/// LSI speed
14pub const LSI_FREQ: u32 = 32_000;
15
16/// System clock mux source
17#[derive(Clone, Copy)]
18pub enum ClockSrc {
19 HSE(Hertz),
20 HSI16(HSI16Prescaler),
21 LSI,
22}
23
24#[derive(Clone, Copy)]
25pub enum HSI16Prescaler {
26 NotDivided,
27 Div2,
28 Div4,
29 Div8,
30 Div16,
31 Div32,
32 Div64,
33 Div128,
34}
35
36impl Into<u8> for HSI16Prescaler {
37 fn into(self) -> u8 {
38 match self {
39 HSI16Prescaler::NotDivided => 0x00,
40 HSI16Prescaler::Div2 => 0x01,
41 HSI16Prescaler::Div4 => 0x02,
42 HSI16Prescaler::Div8 => 0x03,
43 HSI16Prescaler::Div16 => 0x04,
44 HSI16Prescaler::Div32 => 0x05,
45 HSI16Prescaler::Div64 => 0x06,
46 HSI16Prescaler::Div128 => 0x07,
47 }
48 }
49}
50
51/// AHB prescaler
52#[derive(Clone, Copy, PartialEq)]
53pub enum AHBPrescaler {
54 NotDivided,
55 Div2,
56 Div4,
57 Div8,
58 Div16,
59 Div64,
60 Div128,
61 Div256,
62 Div512,
63}
64
65/// APB prescaler
66#[derive(Clone, Copy)]
67pub enum APBPrescaler {
68 NotDivided,
69 Div2,
70 Div4,
71 Div8,
72 Div16,
73}
74
75impl Into<u8> for APBPrescaler {
76 fn into(self) -> u8 {
77 match self {
78 APBPrescaler::NotDivided => 1,
79 APBPrescaler::Div2 => 0x04,
80 APBPrescaler::Div4 => 0x05,
81 APBPrescaler::Div8 => 0x06,
82 APBPrescaler::Div16 => 0x07,
83 }
84 }
85}
86
87impl Into<u8> for AHBPrescaler {
88 fn into(self) -> u8 {
89 match self {
90 AHBPrescaler::NotDivided => 1,
91 AHBPrescaler::Div2 => 0x08,
92 AHBPrescaler::Div4 => 0x09,
93 AHBPrescaler::Div8 => 0x0a,
94 AHBPrescaler::Div16 => 0x0b,
95 AHBPrescaler::Div64 => 0x0c,
96 AHBPrescaler::Div128 => 0x0d,
97 AHBPrescaler::Div256 => 0x0e,
98 AHBPrescaler::Div512 => 0x0f,
99 }
100 }
101}
102
103/// Clocks configutation
104pub struct Config {
105 pub mux: ClockSrc,
106 pub ahb_pre: AHBPrescaler,
107 pub apb_pre: APBPrescaler,
108 pub low_power_run: bool,
109}
110
111impl Default for Config {
112 #[inline]
113 fn default() -> Config {
114 Config {
115 mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
116 ahb_pre: AHBPrescaler::NotDivided,
117 apb_pre: APBPrescaler::NotDivided,
118 low_power_run: false,
119 }
120 }
121}
122
123/// RCC peripheral
124pub struct Rcc<'d> {
125 _rb: peripherals::RCC,
126 phantom: PhantomData<&'d mut peripherals::RCC>,
127}
128
129impl<'d> Rcc<'d> {
130 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
131 unborrow!(rcc);
132 Self {
133 _rb: rcc,
134 phantom: PhantomData,
135 }
136 }
137
138 // Safety: RCC init must have been called
139 pub fn clocks(&self) -> &'static Clocks {
140 unsafe { get_freqs() }
141 }
142}
143
144/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
145pub trait RccExt {
146 fn freeze(self, config: Config) -> Clocks;
147}
148
149impl RccExt for RCC {
150 #[inline]
151 fn freeze(self, cfgr: Config) -> Clocks {
152 let rcc = pac::RCC;
153 let (sys_clk, sw) = match cfgr.mux {
154 ClockSrc::HSI16(div) => {
155 // Enable HSI16
156 let div: u8 = div.into();
157 unsafe {
158 rcc.cr().write(|w| {
159 w.set_hsidiv(div);
160 w.set_hsion(true)
161 });
162 while !rcc.cr().read().hsirdy() {}
163 }
164
165 (HSI_FREQ >> div, 0x00)
166 }
167 ClockSrc::HSE(freq) => {
168 // Enable HSE
169 unsafe {
170 rcc.cr().write(|w| w.set_hseon(true));
171 while !rcc.cr().read().hserdy() {}
172 }
173
174 (freq.0, 0x01)
175 }
176 ClockSrc::LSI => {
177 // Enable LSI
178 unsafe {
179 rcc.csr().write(|w| w.set_lsion(true));
180 while !rcc.csr().read().lsirdy() {}
181 }
182 (LSI_FREQ, 0x03)
183 }
184 };
185
186 unsafe {
187 rcc.cfgr().modify(|w| {
188 w.set_sw(sw.into());
189 w.set_hpre(cfgr.ahb_pre.into());
190 w.set_ppre(cfgr.apb_pre.into());
191 });
192 }
193
194 let ahb_freq: u32 = match cfgr.ahb_pre {
195 AHBPrescaler::NotDivided => sys_clk,
196 pre => {
197 let pre: u8 = pre.into();
198 let pre = 1 << (pre as u32 - 7);
199 sys_clk / pre
200 }
201 };
202
203 let (apb_freq, apb_tim_freq) = match cfgr.apb_pre {
204 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
205 pre => {
206 let pre: u8 = pre.into();
207 let pre: u8 = 1 << (pre - 3);
208 let freq = ahb_freq / pre as u32;
209 (freq, freq * 2)
210 }
211 };
212
213 let pwr = pac::PWR;
214 if cfgr.low_power_run {
215 assert!(sys_clk.hz() <= 2_000_000.hz());
216 unsafe {
217 pwr.cr1().modify(|w| w.set_lpr(true));
218 }
219 }
220
221 Clocks {
222 sys: sys_clk.hz(),
223 ahb: ahb_freq.hz(),
224 apb: apb_freq.hz(),
225 apb_tim: apb_tim_freq.hz(),
226 }
227 }
228}
229
230pub(crate) unsafe fn init(config: Config) {
231 let r = <peripherals::RCC as embassy::util::Steal>::steal();
232 let clocks = r.freeze(config);
233 set_freqs(clocks);
234}