Skip to content

Commit c6c2874

Browse files
committed
Improve configuration of 48 MHz clock.
1 parent 4035c7c commit c6c2874

File tree

2 files changed

+78
-24
lines changed

2 files changed

+78
-24
lines changed

examples/rng.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::hal::prelude::*;
1212
use crate::hal::serial::{Config, Serial};
1313
use crate::hal::stm32;
1414
use hal::hal::blocking::rng::Read;
15+
use hal::rcc::Clk48Source;
1516

1617
macro_rules! uprint {
1718
($serial:expr, $($arg:tt)*) => {
@@ -39,7 +40,7 @@ fn main() -> ! {
3940

4041
let clocks = rcc
4142
.cfgr
42-
.hsi48(true) // needed for RNG
43+
.clk48_source(Clk48Source::Hsi48) // needed for RNG
4344
.sysclk(64.MHz())
4445
.pclk1(32.MHz())
4546
.freeze(&mut flash.acr, &mut pwr);

src/rcc.rs

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl RccExt for RCC {
8181
hse: None,
8282
lse: None,
8383
msi: None,
84-
hsi48: false,
84+
clk48_source: None,
8585
lsi: false,
8686
hclk: None,
8787
pclk1: None,
@@ -148,11 +148,13 @@ impl CRRCR {
148148
}
149149

150150
/// Checks if the 48 MHz HSI is enabled
151+
#[inline]
151152
pub fn is_hsi48_on(&mut self) -> bool {
152153
self.crrcr().read().hsi48on().bit()
153154
}
154155

155156
/// Checks if the 48 MHz HSI is ready
157+
#[inline]
156158
pub fn is_hsi48_ready(&mut self) -> bool {
157159
self.crrcr().read().hsi48rdy().bit()
158160
}
@@ -347,14 +349,14 @@ pub struct CFGR {
347349
hse: Option<HseConfig>,
348350
lse: Option<LseConfig>,
349351
msi: Option<MsiFreq>,
350-
hsi48: bool,
351352
lsi: bool,
352353
hclk: Option<u32>,
353354
pclk1: Option<u32>,
354355
pclk2: Option<u32>,
355356
sysclk: Option<u32>,
356357
pll_source: Option<PllSource>,
357358
pll_config: Option<PllConfig>,
359+
clk48_source: Option<Clk48Source>,
358360
}
359361

360362
impl CFGR {
@@ -382,12 +384,6 @@ impl CFGR {
382384
self
383385
}
384386

385-
/// Enable the 48 MHz USB, RNG, SDMMC HSI clock source. Not available on all stm32l4x6 series
386-
pub fn hsi48(mut self, on: bool) -> Self {
387-
self.hsi48 = on;
388-
self
389-
}
390-
391387
/// Enables the MSI with the specified speed
392388
pub fn msi(mut self, range: MsiFreq) -> Self {
393389
self.msi = Some(range);
@@ -431,6 +427,11 @@ impl CFGR {
431427
self
432428
}
433429

430+
pub fn clk48_source(mut self, source: Clk48Source) -> Self {
431+
self.clk48_source = Some(source);
432+
self
433+
}
434+
434435
/// Freezes the clock configuration, making it effective
435436
pub fn freeze(&self, acr: &mut ACR, pwr: &mut Pwr) -> Clocks {
436437
let rcc = unsafe { &*RCC::ptr() };
@@ -553,18 +554,35 @@ impl CFGR {
553554
while rcc.cr.read().msirdy().bit_is_clear() {}
554555
}
555556

556-
// Turn on USB, RNG Clock using the HSI48 CLK source
557-
if self.hsi48 {
558-
// p. 180 in ref-manual
559-
rcc.crrcr.modify(|_, w| w.hsi48on().set_bit());
557+
// Select 48 MHz clock source for SDMMC, USB, RNG, etc.
558+
match self.clk48_source {
559+
None => {
560+
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b00)) };
561+
}
562+
#[cfg(any(feature = "stm32l496", feature = "stm32l4a6"))]
563+
Some(Clk48Source::Hsi48) => {
564+
// Turn on USB, RNG Clock using the HSI48 CLK source.
560565

561-
// Wait until HSI48 is running
562-
while rcc.crrcr.read().hsi48rdy().bit_is_clear() {}
563-
}
566+
// p. 180 in ref-manual
567+
rcc.crrcr.modify(|_, w| w.hsi48on().set_bit());
568+
569+
// Wait until HSI48 is running.
570+
while rcc.crrcr.read().hsi48rdy().bit_is_clear() {}
564571

565-
// Select MSI as clock source for usb48, rng ...
566-
if let Some(MsiFreq::RANGE48M) = self.msi {
567-
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b11)) };
572+
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b00)) };
573+
}
574+
Some(Clk48Source::PllSai1) => {
575+
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b01)) };
576+
577+
unimplemented!()
578+
}
579+
Some(Clk48Source::Pll) => {
580+
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b10)) };
581+
}
582+
Some(Clk48Source::Msi) => {
583+
assert_eq!(Some(MsiFreq::RANGE48M), self.msi);
584+
unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b11)) };
585+
}
568586
}
569587

570588
//
@@ -716,14 +734,23 @@ impl CFGR {
716734
})
717735
}
718736

737+
let mut pll48m1clk = None;
738+
719739
let sysclk_src_bits;
720740
let mut msi = self.msi;
721741
if let Some(pllconf) = pllconf {
722742
// Sanity-checks per RM0394, 6.4.4 PLL configuration register (RCC_PLLCFGR)
723743
let r = pllconf.r.to_division_factor();
724744
let clock_speed = clock_speed / (pllconf.m as u32 + 1);
725745
let vco = clock_speed * pllconf.n as u32;
726-
let output_clock = vco / r;
746+
let pllclk = vco / r;
747+
748+
let q = (vco + 48_000_000 - 1) / 48_000_000;
749+
pll48m1clk = Some((vco / q).Hz());
750+
751+
if self.clk48_source == Some(Clk48Source::Pll) {
752+
assert_eq!(q, 48_000_000);
753+
}
727754

728755
assert!(r <= 8); // Allowed max output divider
729756
assert!(pllconf.n >= 8); // Allowed min multiplier
@@ -732,7 +759,7 @@ impl CFGR {
732759
assert!(clock_speed <= 16_000_000); // VCO input clock max
733760
assert!(vco >= 64_000_000); // VCO output min
734761
assert!(vco <= 334_000_000); // VCO output max
735-
assert!(output_clock <= 80_000_000); // Max output clock
762+
assert!(pllclk <= 80_000_000); // Max output clock
736763

737764
// use PLL as source
738765
sysclk_src_bits = 0b11;
@@ -750,6 +777,8 @@ impl CFGR {
750777
.bits(pllconf.r.to_bits())
751778
.plln()
752779
.bits(pllconf.n)
780+
.pllq()
781+
.bits(q as u8)
753782
});
754783

755784
rcc.cr.modify(|_, w| w.pllon().set_bit());
@@ -810,15 +839,16 @@ impl CFGR {
810839
lsi: lsi_used,
811840
lse: self.lse.is_some(),
812841
msi,
813-
hsi48: self.hsi48,
814842
pclk1: pclk1.Hz(),
815843
pclk2: pclk2.Hz(),
816844
ppre1,
817845
ppre2,
846+
pll48m1clk,
818847
sysclk: sysclk.Hz(),
819848
timclk1: timclk1.Hz(),
820849
timclk2: timclk2.Hz(),
821850
pll_source: pllconf.map(|_| pll_source),
851+
clk48_source: self.clk48_source,
822852
}
823853
}
824854
}
@@ -900,24 +930,39 @@ impl PllSource {
900930
}
901931
}
902932

933+
#[derive(Clone, Copy, Debug, PartialEq)]
934+
/// 48 MHz clock source used by USB OTG FS, RNG and SDMMC.
935+
pub enum Clk48Source {
936+
/// HSI48 clock
937+
#[cfg(any(feature = "stm32l496", feature = "stm32l4a6"))]
938+
Hsi48,
939+
/// PLLSAI1 “Q” clock (PLL48M2CLK)
940+
PllSai1,
941+
/// PLL “Q” clock (PLL48M1CLK)
942+
Pll,
943+
/// MSI clock
944+
Msi,
945+
}
946+
903947
/// Frozen clock frequencies
904948
///
905949
/// The existence of this value indicates that the clock configuration can no longer be changed
906950
#[derive(Clone, Copy, Debug)]
907951
pub struct Clocks {
908952
hclk: Hertz,
909-
hsi48: bool,
910953
msi: Option<MsiFreq>,
911954
lsi: bool,
912955
lse: bool,
913956
pclk1: Hertz,
914957
pclk2: Hertz,
915958
ppre1: u8,
916959
ppre2: u8,
960+
pll48m1clk: Option<Hertz>,
917961
sysclk: Hertz,
918962
timclk1: Hertz,
919963
timclk2: Hertz,
920964
pll_source: Option<PllSource>,
965+
clk48_source: Option<Clk48Source>,
921966
}
922967

923968
impl Clocks {
@@ -928,7 +973,15 @@ impl Clocks {
928973

929974
/// Returns status of HSI48
930975
pub fn hsi48(&self) -> bool {
931-
self.hsi48
976+
#[cfg(any(feature = "stm32l496", feature = "stm32l4a6"))]
977+
{
978+
self.clk48_source == Some(Clk48Source::Hsi48)
979+
}
980+
981+
#[cfg(not(any(feature = "stm32l496", feature = "stm32l4a6")))]
982+
{
983+
false
984+
}
932985
}
933986

934987
// Returns the status of the MSI

0 commit comments

Comments
 (0)