Skip to content

Commit 80021c8

Browse files
authored
rcc: Add pllsai to CFGR struct and pllsaip as PLL48CLK source (#164)
* rcc: Add pllsai to CFGR struct and pllsaip as PLL48CLK source Signed-off-by: Moritz Scheuren <[email protected]> * Fix example for new PLL48CLK implementation Signed-off-by: Moritz Scheuren <[email protected]> * rcc: pllsai PR feedback implemented (Add comments for clarification) Signed-off-by: Moritz Scheuren <[email protected]>
1 parent d632a5c commit 80021c8

File tree

2 files changed

+162
-32
lines changed

2 files changed

+162
-32
lines changed

examples/usb_serial.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use stm32f7xx_hal::otg_fs::{UsbBus, USB};
2323
use stm32f7xx_hal::otg_hs::{UsbBus, USB};
2424
use stm32f7xx_hal::pac;
2525
use stm32f7xx_hal::prelude::*;
26-
use stm32f7xx_hal::rcc::{HSEClock, HSEClockMode};
26+
use stm32f7xx_hal::rcc::{HSEClock, HSEClockMode, PLL48CLK};
2727
use usb_device::prelude::*;
2828

2929
#[entry]
@@ -36,7 +36,7 @@ fn main() -> ! {
3636
.cfgr
3737
.hse(HSEClock::new(25_000_000.Hz(), HSEClockMode::Bypass))
3838
.use_pll()
39-
.use_pll48clk()
39+
.use_pll48clk(PLL48CLK::Pllq)
4040
.sysclk(216_000_000.Hz())
4141
.freeze();
4242

src/rcc.rs

+160-30
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ impl RccExt for RCC {
3939
lse: None,
4040
lsi: None,
4141
use_pll: false,
42-
use_pll48clk: false,
42+
pll48clk: None,
4343
pllm: 2,
4444
plln: 50,
4545
pllp: PLLP::Div2,
4646
pllq: 2,
47+
use_pllsai: false,
48+
pllsain: 192,
49+
pllsaip: PLLSAIP::Div2,
50+
pllsaiq: 2,
4751
use_plli2s: false,
4852
plli2sr: 2,
4953
plli2sq: 2,
@@ -223,6 +227,24 @@ pub enum MCOPRE {
223227
Div5,
224228
}
225229

230+
/// PLL48CLK clock source selection
231+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
232+
pub enum PLL48CLK {
233+
/// 48 MHz clock from PLLQ is selected
234+
Pllq,
235+
/// 48 MHz clock from PLLSAI is selected
236+
Pllsai,
237+
}
238+
239+
/// PLLSAIP division factors.
240+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
241+
pub enum PLLSAIP {
242+
Div2 = 0b00,
243+
Div4 = 0b01,
244+
Div6 = 0b10,
245+
Div8 = 0b11,
246+
}
247+
226248
/// Microcontroller clock output 1
227249
///
228250
/// Value on reset: HSI
@@ -293,11 +315,15 @@ pub struct CFGR {
293315
lse: Option<LSEClock>,
294316
lsi: Option<Hertz>,
295317
use_pll: bool,
296-
use_pll48clk: bool,
318+
pll48clk: Option<PLL48CLK>,
297319
pllm: u8,
298320
plln: u16,
299321
pllp: PLLP,
300322
pllq: u8,
323+
use_pllsai: bool,
324+
pllsain: u16,
325+
pllsaip: PLLSAIP,
326+
pllsaiq: u8,
301327
use_plli2s: bool,
302328
plli2sr: u8,
303329
plli2sq: u8,
@@ -413,9 +439,9 @@ impl CFGR {
413439
self
414440
}
415441

416-
/// Sets the 48 MHz clock source to the main PLL.
417-
pub fn use_pll48clk(mut self) -> Self {
418-
self.use_pll48clk = true;
442+
/// Sets the 48 MHz clock source.
443+
pub fn use_pll48clk(mut self, pll48clk: PLL48CLK) -> Self {
444+
self.pll48clk = Some(pll48clk);
419445
self
420446
}
421447

@@ -434,7 +460,7 @@ impl CFGR {
434460
///
435461
/// # Panics
436462
///
437-
/// Panics if the multiplication factor isn't between 50 and 432.
463+
/// Panics if the multiplication factor isn't between 50 and 432 (inclusive).
438464
pub fn plln(mut self, plln: u16) -> Self {
439465
assert!((50..=432).contains(&plln));
440466
self.plln = plln;
@@ -450,14 +476,48 @@ impl CFGR {
450476
/// Sets the PLL division factor for the 48 MHz clock.
451477
/// # Panics
452478
///
453-
/// Panics if the division factor isn't between 2 and 15.
479+
/// Panics if the division factor isn't between 2 and 15 (inclusive).
454480
pub fn pllq(mut self, pllq: u8) -> Self {
455481
assert!((2..=15).contains(&pllq));
456482
self.pllq = pllq;
457483
self
458484
}
459485

460-
/// Enables the Plli2S clock source.
486+
/// Enables the PLLSAI clock source.
487+
pub fn use_pllsai(mut self) -> Self {
488+
self.use_pllsai = true;
489+
self
490+
}
491+
492+
/// Sets the PLLSAIN multiplication factor for PLLSAI.
493+
///
494+
/// # Panics
495+
///
496+
/// Panics if the multiplication factor isn't between 50 and 432.
497+
pub fn pllsain(mut self, pllsain: u16) -> Self {
498+
assert!((50..=432).contains(&pllsain));
499+
self.pllsain = pllsain;
500+
self
501+
}
502+
503+
/// Sets the PLLSAIP division factor for PLLSAI.
504+
pub fn pllsaip(mut self, pllsaip: PLLSAIP) -> Self {
505+
self.pllsaip = pllsaip;
506+
self
507+
}
508+
509+
/// Sets the PLLSAIQ division factor for PLLSAIS.
510+
///
511+
/// # Panics
512+
///
513+
/// Panics if the division factor isn't between 2 and 15.
514+
pub fn pllsaiq(mut self, pllsaiq: u8) -> Self {
515+
assert!((2..=15).contains(&pllsaiq));
516+
self.pllsaiq = pllsaiq;
517+
self
518+
}
519+
520+
/// Enables the PLLI2S clock source.
461521
pub fn use_plli2s(mut self) -> Self {
462522
self.use_plli2s = true;
463523
self
@@ -547,13 +607,37 @@ impl CFGR {
547607
};
548608
}
549609

550-
if self.use_pll48clk {
551-
pll48clk_valid = {
552-
let pll48clk =
553-
base_clk as u64 * self.plln as u64 / self.pllm as u64 / self.pllq as u64;
554-
(48_000_000 - 120_000..=48_000_000 + 120_000).contains(&pll48clk)
555-
};
610+
// Check if pll48clk is valid
611+
if let Some(pll48clk) = self.pll48clk {
612+
match pll48clk {
613+
PLL48CLK::Pllq => {
614+
pll48clk_valid = {
615+
let pll48clk = base_clk as u64 * self.plln as u64
616+
/ self.pllm as u64
617+
/ self.pllq as u64;
618+
(48_000_000 - 120_000..=48_000_000 + 120_000).contains(&pll48clk)
619+
}
620+
}
621+
PLL48CLK::Pllsai => {
622+
pll48clk_valid = {
623+
if self.use_pllsai {
624+
let pll48clk = base_clk as u64 * self.pllsain as u64
625+
/ self.pllm as u64
626+
/ match self.pllsaip {
627+
PLLSAIP::Div2 => 2,
628+
PLLSAIP::Div4 => 4,
629+
PLLSAIP::Div6 => 6,
630+
PLLSAIP::Div8 => 8,
631+
};
632+
(48_000_000 - 120_000..=48_000_000 + 120_000).contains(&pll48clk)
633+
} else {
634+
false
635+
}
636+
}
637+
}
638+
}
556639
}
640+
557641
// SYSCLK, must be <= 216 Mhz. By default, HSI/HSE frequency is chosen
558642
assert!(sysclk <= 216_000_000);
559643
let sysclk = sysclk as u32;
@@ -809,7 +893,7 @@ impl CFGR {
809893
Some((sysclk - 1, sysclk + 1))
810894
};
811895

812-
let q = if self.use_pll48clk {
896+
let q = if let Some(PLL48CLK::Pllq) = self.pll48clk {
813897
Some((48_000_000 - 120_000, 48_000_000 + 120_000))
814898
} else {
815899
None
@@ -903,7 +987,7 @@ impl CFGR {
903987
}
904988

905989
// Enable sequence follows by RM 4.1.4 Entering Overdrive mode.
906-
if self.use_pll || self.use_pll48clk {
990+
if self.use_pll || self.pll48clk.is_some() {
907991
// Disable PLL
908992
// Since the main-PLL configuration parameters cannot be changed once PLL is enabled, it is
909993
// recommended to configure PLL before enabling it (selection of the HSI or HSE oscillator as
@@ -967,9 +1051,39 @@ impl CFGR {
9671051
while rcc.csr.read().lsirdy().is_not_ready() {}
9681052
}
9691053

970-
if self.use_pll48clk {
971-
// set source clock for 48 MHz to main PLL
972-
rcc.dckcfgr2.modify(|_, w| w.ck48msel().bit(false));
1054+
if self.use_pllsai {
1055+
let pllsain_freq = match self.hse.as_ref() {
1056+
Some(hse) => hse.freq.integer() as u64 / self.pllm as u64 * self.pllsain as u64,
1057+
None => 16_000_000 / self.pllm as u64 * self.pllsain as u64,
1058+
};
1059+
let pllsaip_freq = pllsain_freq
1060+
/ match self.pllsaip {
1061+
PLLSAIP::Div2 => 2,
1062+
PLLSAIP::Div4 => 4,
1063+
PLLSAIP::Div6 => 6,
1064+
PLLSAIP::Div8 => 8,
1065+
};
1066+
// let pllsaiq_freq = pllsain_freq / self.pllsaiq as u64;
1067+
1068+
// The reference manual (RM0410 Rev 4, Page 212), says the following
1069+
// "Caution: The software has to set these bits correctly to ensure that the VCO output frequency is between 100 and 432 MHz.",
1070+
// but STM32CubeMX states 192 MHz as the minimum. SSo the stricter requirement was chosen.
1071+
assert!((192_000_000..=432_000_000).contains(&pllsain_freq));
1072+
assert!(pllsaip_freq <= 48_000_000);
1073+
1074+
rcc.pllsaicfgr.modify(|_, w| unsafe {
1075+
w.pllsain().bits(self.pllsain);
1076+
w.pllsaip().bits(self.pllsaip as u8);
1077+
w.pllsaiq().bits(self.pllsaiq)
1078+
});
1079+
rcc.cr.modify(|_, w| w.pllsaion().on());
1080+
}
1081+
1082+
if let Some(pll48clk) = self.pll48clk {
1083+
match pll48clk {
1084+
PLL48CLK::Pllq => rcc.dckcfgr2.modify(|_, w| w.ck48msel().bit(false)),
1085+
PLL48CLK::Pllsai => rcc.dckcfgr2.modify(|_, w| w.ck48msel().bit(true)),
1086+
}
9731087
}
9741088

9751089
if self.use_plli2s {
@@ -1365,7 +1479,7 @@ mod tests {
13651479

13661480
#[test]
13671481
fn test_rcc_calc1() {
1368-
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLLP};
1482+
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLL48CLK, PLLP, PLLSAIP};
13691483

13701484
let cfgr = CFGR {
13711485
hse: None,
@@ -1376,11 +1490,15 @@ mod tests {
13761490
lse: None,
13771491
lsi: None,
13781492
use_pll: false,
1379-
use_pll48clk: false,
1493+
pll48clk: None,
13801494
pllm: 2,
13811495
plln: 50,
13821496
pllp: PLLP::Div2,
13831497
pllq: 2,
1498+
use_pllsai: false,
1499+
pllsain: 192,
1500+
pllsaip: PLLSAIP::Div2,
1501+
pllsaiq: 2,
13841502
use_plli2s: false,
13851503
plli2sr: 2,
13861504
plli2sq: 2,
@@ -1394,7 +1512,7 @@ mod tests {
13941512
let mut cfgr = cfgr
13951513
.hse(HSEClock::new(25_000_000.Hz(), HSEClockMode::Bypass))
13961514
.use_pll()
1397-
.use_pll48clk()
1515+
.use_pll48clk(PLL48CLK::Pllq)
13981516
.sysclk(216_000_000.Hz());
13991517
cfgr.pll_configure();
14001518

@@ -1407,7 +1525,7 @@ mod tests {
14071525

14081526
#[test]
14091527
fn test_rcc_calc2() {
1410-
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLLP};
1528+
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLL48CLK, PLLP, PLLSAIP};
14111529

14121530
let cfgr = CFGR {
14131531
hse: None,
@@ -1418,11 +1536,15 @@ mod tests {
14181536
lse: None,
14191537
lsi: None,
14201538
use_pll: false,
1421-
use_pll48clk: false,
1539+
pll48clk: None,
14221540
pllm: 2,
14231541
plln: 50,
14241542
pllp: PLLP::Div2,
14251543
pllq: 2,
1544+
use_pllsai: false,
1545+
pllsain: 192,
1546+
pllsaip: PLLSAIP::Div2,
1547+
pllsaiq: 2,
14261548
use_plli2s: false,
14271549
plli2sr: 2,
14281550
plli2sq: 2,
@@ -1435,7 +1557,7 @@ mod tests {
14351557

14361558
let mut cfgr = cfgr
14371559
.hse(HSEClock::new(25_000_000.Hz(), HSEClockMode::Bypass))
1438-
.use_pll48clk()
1560+
.use_pll48clk(PLL48CLK::Pllq)
14391561
.sysclk(216_000_000.Hz());
14401562
cfgr.pll_configure();
14411563

@@ -1448,7 +1570,7 @@ mod tests {
14481570

14491571
#[test]
14501572
fn test_rcc_calc3() {
1451-
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLLP};
1573+
use super::{HSEClock, HSEClockMode, MCO1, MCO2, MCOPRE, PLL48CLK, PLLP, PLLSAIP};
14521574

14531575
let cfgr = CFGR {
14541576
hse: None,
@@ -1459,11 +1581,15 @@ mod tests {
14591581
lse: None,
14601582
lsi: None,
14611583
use_pll: false,
1462-
use_pll48clk: false,
1584+
pll48clk: None,
14631585
pllm: 2,
14641586
plln: 50,
14651587
pllp: PLLP::Div2,
14661588
pllq: 2,
1589+
use_pllsai: false,
1590+
pllsain: 192,
1591+
pllsaip: PLLSAIP::Div2,
1592+
pllsaiq: 2,
14671593
use_plli2s: false,
14681594
plli2sr: 2,
14691595
plli2sq: 2,
@@ -1476,7 +1602,7 @@ mod tests {
14761602

14771603
let mut cfgr = cfgr
14781604
.hse(HSEClock::new(25_000_000.Hz(), HSEClockMode::Bypass))
1479-
.use_pll48clk()
1605+
.use_pll48clk(PLL48CLK::Pllq)
14801606
.set_defaults();
14811607
cfgr.pll_configure();
14821608

@@ -1489,7 +1615,7 @@ mod tests {
14891615

14901616
#[test]
14911617
fn test_rcc_default() {
1492-
use super::{MCO1, MCO2, MCOPRE, PLLP};
1618+
use super::{MCO1, MCO2, MCOPRE, PLLP, PLLSAIP};
14931619

14941620
let mut cfgr = CFGR {
14951621
hse: None,
@@ -1500,11 +1626,15 @@ mod tests {
15001626
lse: None,
15011627
lsi: None,
15021628
use_pll: false,
1503-
use_pll48clk: false,
1629+
pll48clk: None,
15041630
pllm: 2,
15051631
plln: 50,
15061632
pllp: PLLP::Div2,
15071633
pllq: 2,
1634+
use_pllsai: false,
1635+
pllsain: 192,
1636+
pllsaip: PLLSAIP::Div2,
1637+
pllsaiq: 2,
15081638
use_plli2s: false,
15091639
plli2sr: 2,
15101640
plli2sq: 2,

0 commit comments

Comments
 (0)