Skip to content

Commit 1924bb1

Browse files
bentwiretherealprof
authored andcommitted
Stm32f04x additions for RCC (#17)
Some new logic to select clock source
1 parent 3691709 commit 1924bb1

File tree

1 file changed

+124
-18
lines changed

1 file changed

+124
-18
lines changed

src/rcc.rs

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::cmp;
12
use crate::time::Hertz;
23

34
/// Extension trait that constrains the `RCC` peripheral
@@ -14,6 +15,8 @@ impl RccExt for crate::stm32::RCC {
1415
hclk: None,
1516
pclk: None,
1617
sysclk: None,
18+
enable_hsi: true,
19+
enable_hsi48: false,
1720
},
1821
}
1922
}
@@ -26,12 +29,32 @@ pub struct Rcc {
2629

2730
#[allow(unused)]
2831
const HSI: u32 = 8_000_000; // Hz
32+
#[allow(unused)]
33+
const HSI48: u32 = 48_000_000; // Hz - (available on STM32F04x, STM32F07x and STM32F09x devices only)
34+
35+
#[allow(unused)]
36+
enum SysClkSource {
37+
HSI = 0b00,
38+
HSE = 0b01,
39+
PLL = 0b10,
40+
HSI48 = 0b11,
41+
}
42+
43+
#[allow(unused)]
44+
enum PllSource {
45+
HSI_DIV2 = 0b00,
46+
HSI = 0b01,
47+
HSE = 0b10,
48+
HSI48 = 0b11,
49+
}
2950

3051
#[allow(unused)]
3152
pub struct CFGR {
3253
hclk: Option<u32>,
3354
pclk: Option<u32>,
3455
sysclk: Option<u32>,
56+
enable_hsi: bool,
57+
enable_hsi48: bool,
3558
}
3659

3760
#[cfg(feature = "device-selected")]
@@ -60,20 +83,58 @@ impl CFGR {
6083
self
6184
}
6285

86+
pub fn enable_hsi(mut self, is_enabled: bool) -> Self {
87+
self.enable_hsi = is_enabled;
88+
self
89+
}
90+
91+
#[cfg(feature = "stm32f042")]
92+
pub fn enable_hsi48(mut self, is_enabled: bool) -> Self {
93+
self.enable_hsi48 = is_enabled;
94+
self
95+
}
96+
6397
pub fn freeze(self) -> Clocks {
64-
let pllmul = (4 * self.sysclk.unwrap_or(HSI) + HSI) / HSI / 2;
65-
let pllmul = core::cmp::min(core::cmp::max(pllmul, 2), 16);
66-
let sysclk = pllmul * HSI / 2;
98+
// Default to lowest frequency clock on all systems.
99+
let sysclk = self.sysclk.unwrap_or(HSI);
100+
101+
let r_sysclk; // The "real" sysclock value, calculated below
102+
let src_clk_freq; // Frequency of source clock for PLL and etc, HSI, or HSI48 on supported systems.
103+
let pllmul_bits;
67104

68-
let pllmul_bits = if pllmul == 2 {
69-
None
105+
// Select clock source based on user input and capability
106+
// Highest selected frequency source available takes precedent.
107+
// For F04x, F07x, F09x parts, use HSI48 if requested.
108+
if self.enable_hsi48 {
109+
src_clk_freq = HSI48; // Use HSI48 if requested and available.
110+
} else if self.enable_hsi {
111+
src_clk_freq = HSI; // HSI if requested
70112
} else {
71-
Some(pllmul as u8 - 2)
72-
};
113+
src_clk_freq = HSI; // If no clock source is selected use HSI.
114+
}
115+
116+
// Pll check
117+
if sysclk == src_clk_freq {
118+
// Bypass pll if src clk and requested sysclk are the same, to save power.
119+
// The only reason to override this behaviour is if the sysclk source were HSI, and you
120+
// were running the USB off the PLL...
121+
pllmul_bits = None;
122+
r_sysclk = src_clk_freq;
123+
} else {
124+
let pllmul = (4 * self.sysclk.unwrap_or(src_clk_freq) + src_clk_freq) / src_clk_freq / 2;
125+
let pllmul = cmp::min(cmp::max(pllmul, 2), 16);
126+
r_sysclk = pllmul * src_clk_freq / 2;
127+
128+
pllmul_bits = if pllmul == 2 {
129+
None
130+
} else {
131+
Some(pllmul as u8 - 2)
132+
};
133+
}
73134

74135
let hpre_bits = self
75136
.hclk
76-
.map(|hclk| match sysclk / hclk {
137+
.map(|hclk| match r_sysclk / hclk {
77138
0 => unreachable!(),
78139
1 => 0b0111,
79140
2 => 0b1000,
@@ -119,24 +180,69 @@ impl CFGR {
119180
}
120181

121182
let rcc = unsafe { &*crate::stm32::RCC::ptr() };
122-
if let Some(pllmul_bits) = pllmul_bits {
123-
// use PLL as source
124183

184+
// Set up rcc based on above calculated configuration.
185+
186+
// Enable requested clock sources
187+
// HSI
188+
if self.enable_hsi {
189+
rcc.cr.write(|w| w.hsion().set_bit());
190+
while rcc.cr.read().hsirdy().bit_is_clear() { }
191+
}
192+
// HSI48
193+
if self.enable_hsi48 {
194+
rcc.cr2.modify(|_, w| w.hsi48on().set_bit());
195+
while rcc.cr2.read().hsi48rdy().bit_is_clear() { }
196+
}
197+
198+
// Enable PLL
199+
if let Some(pllmul_bits) = pllmul_bits {
125200
rcc.cfgr.write(|w| unsafe { w.pllmul().bits(pllmul_bits) });
126201

127-
rcc.cr.write(|w| w.pllon().set_bit());
202+
// Set PLL source based on configuration.
203+
if self.enable_hsi48 {
204+
rcc.cfgr.modify(|_, w| w.pllsrc().bits(PllSource::HSI48 as u8));
205+
} else if self.enable_hsi {
206+
rcc.cfgr.modify(|_, w| w.pllsrc().bits(PllSource::HSI_DIV2 as u8));
207+
} else {
208+
rcc.cfgr.modify(|_, w| w.pllsrc().bits(PllSource::HSI_DIV2 as u8));
209+
}
128210

129-
while rcc.cr.read().pllrdy().bit_is_clear() {}
211+
rcc.cr.write(|w| w.pllon().set_bit());
212+
while rcc.cr.read().pllrdy().bit_is_clear() { }
130213

131214
rcc.cfgr.modify(|_, w| unsafe {
132-
w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().bits(2)
215+
w.ppre()
216+
.bits(ppre_bits)
217+
.hpre()
218+
.bits(hpre_bits)
219+
.sw()
220+
.bits(SysClkSource::PLL as u8)
133221
});
134-
} else {
135-
// use HSI as source
136-
rcc.cfgr
137-
.write(|w| unsafe { w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().bits(0) });
138-
}
139222

223+
} else { // No PLL required.
224+
// Setup requested clocks.
225+
if self.enable_hsi48 {
226+
rcc.cfgr.modify(|_, w| unsafe {
227+
w.ppre().bits(ppre_bits)
228+
.hpre().bits(hpre_bits)
229+
.sw().bits(SysClkSource::HSI48 as u8)
230+
});
231+
} else if self.enable_hsi {
232+
rcc.cfgr.modify(|_, w| unsafe {
233+
w.ppre().bits(ppre_bits)
234+
.hpre().bits(hpre_bits)
235+
.sw().bits(SysClkSource::HSI as u8)
236+
});
237+
} else { // Default to HSI
238+
rcc.cfgr.modify(|_, w| unsafe {
239+
w.ppre().bits(ppre_bits)
240+
.hpre().bits(hpre_bits)
241+
.sw().bits(SysClkSource::HSI as u8)
242+
});
243+
}
244+
}
245+
140246
Clocks {
141247
hclk: Hertz(hclk),
142248
pclk: Hertz(pclk),

0 commit comments

Comments
 (0)