1+ use core:: cmp;
12use 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) ]
2831const 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) ]
3152pub 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