aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-06-22 20:07:48 -0300
committerThales Fragoso <[email protected]>2021-06-24 19:21:56 -0300
commit409884be2a749ddf91733dd3595c28c800358c32 (patch)
tree904a004c8a488701edd82fa5e6a62d24b56e5fee
parent797534d1a623b8dc0390e1df2b389612595a8643 (diff)
Add F0 RCC
-rw-r--r--embassy-stm32/src/rcc/f0/mod.rs231
-rw-r--r--embassy-stm32/src/rcc/mod.rs8
m---------stm32-data0
3 files changed, 238 insertions, 1 deletions
diff --git a/embassy-stm32/src/rcc/f0/mod.rs b/embassy-stm32/src/rcc/f0/mod.rs
new file mode 100644
index 000000000..8ddacb8ef
--- /dev/null
+++ b/embassy-stm32/src/rcc/f0/mod.rs
@@ -0,0 +1,231 @@
1use core::marker::PhantomData;
2
3use embassy::util::Unborrow;
4
5use crate::pac::{DBGMCU, FLASH, RCC};
6use crate::peripherals;
7use crate::time::Hertz;
8
9use super::{set_freqs, Clocks};
10
11const HSI: u32 = 8_000_000;
12
13/// Configuration of the clocks
14///
15/// hse takes precedence over hsi48 if both are enabled
16#[non_exhaustive]
17#[derive(Default)]
18pub struct Config {
19 pub hse: Option<Hertz>,
20 pub bypass_hse: bool,
21 pub usb_pll: bool,
22
23 #[cfg(rcc_f0)]
24 pub hsi48: bool,
25
26 pub sys_ck: Option<Hertz>,
27 pub hclk: Option<Hertz>,
28 pub pclk: Option<Hertz>,
29 pub enable_debug_wfe: bool,
30}
31
32pub struct Rcc<'d> {
33 inner: PhantomData<&'d ()>,
34 config: Config,
35}
36
37impl<'d> Rcc<'d> {
38 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
39 Self {
40 inner: PhantomData,
41 config,
42 }
43 }
44
45 pub fn freeze(self) -> Clocks {
46 use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
47
48 let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI);
49
50 let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
51 #[cfg(rcc_f0)]
52 if self.config.hsi48 {
53 return (48_000_000, true);
54 }
55 (HSI, false)
56 });
57
58 let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
59 (None, sysclk)
60 } else {
61 let prediv = if self.config.hse.is_some() { 1 } else { 2 };
62 let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
63 let pllmul = pllmul.max(2).min(16);
64
65 let pllmul_bits = pllmul as u8 - 2;
66 let real_sysclk = pllmul * src_clk / prediv;
67 (Some(pllmul_bits), real_sysclk)
68 };
69
70 let hpre_bits = self
71 .config
72 .hclk
73 .map(|hclk| match real_sysclk / hclk.0 {
74 0 => unreachable!(),
75 1 => 0b0111,
76 2 => 0b1000,
77 3..=5 => 0b1001,
78 6..=11 => 0b1010,
79 12..=39 => 0b1011,
80 40..=95 => 0b1100,
81 96..=191 => 0b1101,
82 192..=383 => 0b1110,
83 _ => 0b1111,
84 })
85 .unwrap_or(0b0111);
86 let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
87
88 let ppre_bits = self
89 .config
90 .pclk
91 .map(|pclk| match hclk / pclk.0 {
92 0 => unreachable!(),
93 1 => 0b011,
94 2 => 0b100,
95 3..=5 => 0b101,
96 6..=11 => 0b110,
97 _ => 0b111,
98 })
99 .unwrap_or(0b011);
100
101 let ppre: u8 = 1 << (ppre_bits - 0b011);
102 let pclk = hclk / u32::from(ppre);
103
104 let timer_mul = if ppre == 1 { 1 } else { 2 };
105
106 // NOTE(safety) Atomic write
107 unsafe {
108 FLASH.acr().write(|w| {
109 let latency = if real_sysclk <= 24_000_000 {
110 0
111 } else if real_sysclk <= 48_000_000 {
112 1
113 } else {
114 2
115 };
116 w.latency().0 = latency;
117 });
118 }
119
120 // NOTE(unsafe) We have exclusive access to the RCC
121 unsafe {
122 match (self.config.hse.is_some(), use_hsi48) {
123 (true, _) => {
124 RCC.cr().modify(|w| {
125 w.set_csson(true);
126 w.set_hseon(true);
127
128 if self.config.bypass_hse {
129 w.set_hsebyp(Hsebyp::BYPASSED);
130 }
131 });
132 while !RCC.cr().read().hserdy() {}
133
134 if pllmul_bits.is_some() {
135 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
136 }
137 }
138 (false, true) => {
139 // use_hsi48 will always be false for rcc_f0x0
140 #[cfg(rcc_f0)]
141 RCC.cr2().modify(|w| w.set_hsi48on(true));
142 #[cfg(rcc_f0)]
143 while !RCC.cr2().read().hsi48rdy() {}
144
145 #[cfg(rcc_f0)]
146 if pllmul_bits.is_some() {
147 RCC.cfgr()
148 .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
149 }
150 }
151 _ => {
152 RCC.cr().modify(|w| w.set_hsion(true));
153 while !RCC.cr().read().hsirdy() {}
154
155 if pllmul_bits.is_some() {
156 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
157 }
158 }
159 }
160
161 if self.config.usb_pll {
162 RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
163 }
164 // TODO: Option to use CRS (Clock Recovery)
165
166 if let Some(pllmul_bits) = pllmul_bits {
167 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
168
169 RCC.cr().modify(|w| w.set_pllon(true));
170 while !RCC.cr().read().pllrdy() {}
171
172 RCC.cfgr().modify(|w| {
173 w.set_ppre(Ppre(ppre_bits));
174 w.set_hpre(Hpre(hpre_bits));
175 w.set_sw(Sw::PLL)
176 });
177 } else {
178 RCC.cfgr().modify(|w| {
179 w.set_ppre(Ppre(ppre_bits));
180 w.set_hpre(Hpre(hpre_bits));
181
182 if self.config.hse.is_some() {
183 w.set_sw(Sw::HSE);
184 } else if use_hsi48 {
185 #[cfg(rcc_f0)]
186 w.set_sw(Sw::HSI48);
187 } else {
188 w.set_sw(Sw::HSI)
189 }
190 })
191 }
192
193 if self.config.enable_debug_wfe {
194 RCC.ahbenr().modify(|w| w.set_dmaen(true));
195
196 critical_section::with(|_| {
197 DBGMCU.cr().modify(|w| {
198 w.set_dbg_standby(true);
199 w.set_dbg_stop(true);
200 });
201 });
202 }
203 }
204
205 Clocks {
206 sys: Hertz(real_sysclk),
207 apb1: Hertz(pclk),
208 apb1_tim: Hertz(pclk * timer_mul),
209 apb2_tim: Hertz(0),
210 ahb: Hertz(hclk),
211 }
212 }
213}
214
215pub unsafe fn init(config: Config) {
216 RCC.ahbenr().modify(|w| {
217 w.set_iopaen(true);
218 w.set_iopben(true);
219 w.set_iopcen(true);
220 w.set_iopden(true);
221
222 #[cfg(rcc_f0)]
223 w.set_iopeen(true);
224
225 w.set_iopfen(true);
226 });
227
228 let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
229 let clocks = rcc.freeze();
230 set_freqs(clocks);
231}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index e84021272..91e8b5bef 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -9,11 +9,14 @@ mod types;
9pub struct Clocks { 9pub struct Clocks {
10 pub sys: Hertz, 10 pub sys: Hertz,
11 pub apb1: Hertz, 11 pub apb1: Hertz,
12
13 #[cfg(not(any(rcc_f0, rcc_f0x0)))]
12 pub apb2: Hertz, 14 pub apb2: Hertz,
15
13 pub apb1_tim: Hertz, 16 pub apb1_tim: Hertz,
14 pub apb2_tim: Hertz, 17 pub apb2_tim: Hertz,
15 18
16 #[cfg(any(rcc_l0))] 19 #[cfg(any(rcc_l0, rcc_f0, rcc_f0x0))]
17 pub ahb: Hertz, 20 pub ahb: Hertz,
18 21
19 #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))] 22 #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))]
@@ -65,6 +68,9 @@ cfg_if::cfg_if! {
65 } else if #[cfg(rcc_wl5x)] { 68 } else if #[cfg(rcc_wl5x)] {
66 mod wl5x; 69 mod wl5x;
67 pub use wl5x::*; 70 pub use wl5x::*;
71 } else if #[cfg(any(rcc_f0, rcc_f0x0))] {
72 mod f0;
73 pub use f0::*;
68 } 74 }
69} 75}
70 76
diff --git a/stm32-data b/stm32-data
Subproject 18f86c83123771048f971350c99c4f810385d7d Subproject eb76ee900ac67b51497196572250323e82666b4