Skip to content

Commit c4c48df

Browse files
committed
Make freeze() fallible
1 parent 54e8261 commit c4c48df

File tree

7 files changed

+105
-50
lines changed

7 files changed

+105
-50
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Breaking changes
11+
12+
- `rcc.cfgr.freeze(...)` is now fallible
13+
- As the clock tree can be configured in many wrong ways,
14+
this change will make it obvious, that the clock is misconfigured.
15+
No more nasty hidden asserts in `rcc`
16+
1017
### Added
1118

1219
- Support for 16-bit words with SPI ([#107](https://github.com/stm32-rs/stm32f3xx-hal/pull/107))

examples/adc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn main() -> ! {
1616
// Get peripherals, clocks and freeze them
1717
let mut dp = pac::Peripherals::take().unwrap();
1818
let mut rcc = dp.RCC.constrain();
19-
let clocks = rcc.cfgr.freeze(&mut dp.FLASH.constrain().acr);
19+
let clocks = rcc.cfgr.freeze(&mut dp.FLASH.constrain().acr).unwrap();
2020

2121
// set up adc1
2222
let mut adc1 = adc::Adc::adc1(

examples/pwm.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ fn main() -> ! {
2727
// Configure our clocks
2828
let mut flash = dp.FLASH.constrain();
2929
let mut rcc = dp.RCC.constrain();
30-
let clocks = rcc.cfgr.sysclk(16.mhz()).freeze(&mut flash.acr);
30+
let clocks = rcc
31+
.cfgr
32+
.sysclk(16.mhz())
33+
.freeze(&mut flash.acr)
34+
.unwrap_or_default();
3135

3236
// Prep the pins we need in their correct alternate function
3337
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);

examples/serial_dma.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn main() -> ! {
1717

1818
let mut flash = dp.FLASH.constrain();
1919
let mut rcc = dp.RCC.constrain();
20-
let clocks = rcc.cfgr.freeze(&mut flash.acr);
20+
let clocks = rcc.cfgr.freeze(&mut flash.acr).unwrap();
2121

2222
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
2323

examples/spi.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ fn main() -> ! {
2626
.use_hse(8.mhz())
2727
.sysclk(48.mhz())
2828
.pclk1(24.mhz())
29-
.freeze(&mut flash.acr);
29+
.freeze(&mut flash.acr)
30+
.unwrap();
3031

3132
// Configure pins for SPI
3233
let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);

examples/usb_serial.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ fn main() -> ! {
3030
.sysclk(48.mhz())
3131
.pclk1(24.mhz())
3232
.pclk2(24.mhz())
33-
.freeze(&mut flash.acr);
33+
.freeze(&mut flash.acr)
34+
.unwrap();
3435

3536
assert!(clocks.usbclk_valid());
3637

src/rcc.rs

Lines changed: 87 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
//! Reset and Clock Control
22
3+
use core::default;
4+
35
use crate::pac::{
46
rcc::{self, cfgr, cfgr2},
57
RCC,
68
};
79

810
use crate::flash::ACR;
911
use crate::time::Hertz;
12+
use crate::time::U32Ext;
13+
14+
#[derive(Copy, Clone, Debug)]
15+
pub enum RccError {
16+
PllMaxExceeded,
17+
Pclk1MaxExceeded,
18+
Pclk2MaxExceeded,
19+
SysclkMaxExceeded,
20+
HclkMaxExceeded,
21+
}
1022

1123
/// Extension trait that constrains the `RCC` peripheral
1224
pub trait RccExt {
@@ -357,7 +369,7 @@ impl CFGR {
357369
feature = "stm32f303xe",
358370
feature = "stm32f398"
359371
)))]
360-
fn calc_pll(&self, sysclk: u32) -> (u32, PllConfig) {
372+
fn calc_pll(&self, sysclk: u32) -> Result<(u32, PllConfig), RccError> {
361373
let pllsrcclk = self.hse.unwrap_or(HSI / 2);
362374
// Get the optimal value for the pll divisor (PLL_DIV) and multiplier (PLL_MUL)
363375
// Only for HSE PLL_DIV can be changed
@@ -377,22 +389,26 @@ impl CFGR {
377389
divisor *= 2;
378390
}
379391

380-
// PLL_MUL maximal value is 16
381-
assert!(divisor <= 16);
382-
// PRE_DIV maximal value is 16
383-
assert!(multiplier <= 16);
392+
// PLL_MUL and PLLD_DIV maximal values are 16
393+
if multiplier <= 16 || divisor <= 16 {
394+
return Err(RccError::PllMaxExceeded);
395+
}
384396

385397
(multiplier, Some(divisor))
386398
}
387399
// HSI division is always divided by 2 and has no adjustable division
388400
else {
389401
let pll_mul = sysclk / pllsrcclk;
390-
assert!(pll_mul <= 16);
402+
if pll_mul <= 16 {
403+
return Err(RccError::PllMaxExceeded);
404+
}
391405
(pll_mul, None)
392406
};
393407

394408
let sysclk = (pllsrcclk / pll_div.unwrap_or(1)) * pll_mul;
395-
assert!(sysclk <= 72_000_000);
409+
if sysclk <= 72_000_000 {
410+
return Err(RccError::SysclkMaxExceeded);
411+
}
396412

397413
let pll_src = if self.hse.is_some() {
398414
cfgr::PLLSRC_A::HSE_DIV_PREDIV
@@ -404,14 +420,14 @@ impl CFGR {
404420
let pll_mul_bits = into_pll_mul(pll_mul as u8);
405421
let pll_div_bits = pll_div.map(|pll_div| into_pre_div(pll_div as u8));
406422

407-
(
423+
Ok((
408424
sysclk,
409425
PllConfig {
410426
src: pll_src,
411427
mul: pll_mul_bits,
412428
div: pll_div_bits,
413429
},
414-
)
430+
))
415431
}
416432

417433
/// Calculate the values for the pll multiplier (PLLMUL) and the pll divisor (PLLDIV).
@@ -423,7 +439,7 @@ impl CFGR {
423439
/// the external oscillator (HSE).
424440
/// After this the system clock frequency (SYSCLK) can be changed via a division and a
425441
/// multiplication block.
426-
/// It can be divided from with values 1..16 and multiplied from 2..16.
442+
/// It can be divided from with values `1..16` and multiplied from `2..16`.
427443
///
428444
/// To determine the optimal values, the greatest common divisor is calculated and the
429445
/// limitations of the possible values are taken into considiration.
@@ -434,7 +450,7 @@ impl CFGR {
434450
feature = "stm32f303xe",
435451
feature = "stm32f398",
436452
))]
437-
fn calc_pll(&self, sysclk: u32) -> (u32, PllConfig) {
453+
fn calc_pll(&self, sysclk: u32) -> Result<(u32, PllConfig), RccError> {
438454
let pllsrcclk = self.hse.unwrap_or(HSI);
439455

440456
let (pll_mul, pll_div) = {
@@ -451,17 +467,18 @@ impl CFGR {
451467
divisor *= 2;
452468
}
453469

454-
// PLL_MUL maximal value is 16
455-
assert!(multiplier <= 16);
456-
457-
// PRE_DIV maximal value is 16
458-
assert!(divisor <= 16);
470+
// PLL_MUL and PLLD_DIV maximal values are 16
471+
if multiplier <= 16 || divisor <= 16 {
472+
return Err(RccError::PllMaxExceeded);
473+
}
459474

460475
(multiplier, divisor)
461476
};
462477

463478
let sysclk = (pllsrcclk / pll_div) * pll_mul;
464-
assert!(sysclk <= 72_000_000);
479+
if sysclk <= 72_000_000 {
480+
return Err(RccError::SysclkMaxExceeded);
481+
}
465482

466483
// Select hardware clock source of the PLL
467484
// TODO Check whether HSI_DIV2 could be useful
@@ -475,25 +492,25 @@ impl CFGR {
475492
let pll_mul_bits = into_pll_mul(pll_mul as u8);
476493
let pll_div_bits = into_pre_div(pll_div as u8);
477494

478-
(
495+
Ok((
479496
sysclk,
480497
PllConfig {
481498
src: pll_src,
482499
mul: pll_mul_bits,
483500
div: Some(pll_div_bits),
484501
},
485-
)
502+
))
486503
}
487504

488505
/// Get the system clock, the system clock source and the pll_options, if needed.
489506
///
490507
/// The system clock source is determined by the chosen system clock and the provided hardware
491508
/// clock.
492509
/// This function does only chose the PLL if needed, otherwise it will use the oscillator clock as system clock.
493-
fn get_sysclk(&self) -> (u32, cfgr::SW_A, Option<PllConfig>) {
510+
fn get_sysclk(&self) -> Result<(u32, cfgr::SW_A, Option<PllConfig>), RccError> {
494511
// If a sysclk is given, check if the PLL has to be used,
495512
// else select the system clock source, which is either HSI or HSE.
496-
match (self.sysclk, self.hse) {
513+
Ok(match (self.sysclk, self.hse) {
497514
// No need to use the PLL
498515
// PLL is needed for USB, but we can make this assumption, to not use PLL here,
499516
// because the two valid USB clocks, 72 Mhz and 48 Mhz, can't be generated
@@ -503,23 +520,22 @@ impl CFGR {
503520
// No need to use the PLL
504521
(Some(sysclk), None) if sysclk == HSI => (HSI, cfgr::SW_A::HSI, None),
505522
(Some(sysclk), _) => {
506-
let (sysclk, pll_config) = self.calc_pll(sysclk);
523+
let (sysclk, pll_config) = self.calc_pll(sysclk)?;
507524
(sysclk, cfgr::SW_A::PLL, Some(pll_config))
508525
}
509526
// Use HSE as system clock
510527
(None, Some(hse)) => (hse, cfgr::SW_A::HSE, None),
511528
// Use HSI as system clock
512529
(None, None) => (HSI, cfgr::SW_A::HSI, None),
513-
}
530+
})
514531
}
515532

516533
/// Freezes the clock configuration, making it effective
517-
pub fn freeze(self, acr: &mut ACR) -> Clocks {
518-
let (sysclk, sysclk_source, pll_config) = self.get_sysclk();
534+
pub fn freeze(self, acr: &mut ACR) -> Result<Clocks, RccError> {
535+
let (sysclk, sysclk_source, pll_config) = self.get_sysclk()?;
519536

520-
let (hpre_bits, hpre) = self
521-
.hclk
522-
.map(|hclk| match sysclk / hclk {
537+
let (hpre_bits, hpre) = if let Some(hclk) = self.hclk {
538+
match sysclk.checked_div(hclk).ok_or(RccError::HclkMaxExceeded)? {
523539
0 => unreachable!(),
524540
1 => (cfgr::HPRE_A::DIV1, 1),
525541
2 => (cfgr::HPRE_A::DIV2, 2),
@@ -529,45 +545,56 @@ impl CFGR {
529545
40..=95 => (cfgr::HPRE_A::DIV64, 64),
530546
96..=191 => (cfgr::HPRE_A::DIV128, 128),
531547
192..=383 => (cfgr::HPRE_A::DIV256, 256),
548+
// TODO: Add Error case, if result is to high
532549
_ => (cfgr::HPRE_A::DIV512, 512),
533-
})
534-
.unwrap_or((cfgr::HPRE_A::DIV1, 1));
550+
}
551+
} else {
552+
(cfgr::HPRE_A::DIV1, 1)
553+
};
535554

536555
let hclk: u32 = sysclk / hpre;
537556

538-
assert!(hclk <= 72_000_000);
557+
if hclk <= 72_000_000 {
558+
return Err(RccError::HclkMaxExceeded);
559+
}
539560

540-
let (ppre1_bits, ppre1) = self
541-
.pclk1
542-
.map(|pclk1| match hclk / pclk1 {
561+
let (ppre1_bits, ppre1) = if let Some(pclk1) = self.pclk1 {
562+
match hclk.checked_div(pclk1).ok_or(RccError::Pclk1MaxExceeded)? {
543563
0 => unreachable!(),
544564
1 => (cfgr::PPRE1_A::DIV1, 1),
545565
2 => (cfgr::PPRE1_A::DIV2, 2),
546566
3..=5 => (cfgr::PPRE1_A::DIV4, 4),
547567
6..=11 => (cfgr::PPRE1_A::DIV8, 8),
548568
_ => (cfgr::PPRE1_A::DIV16, 16),
549-
})
550-
.unwrap_or((cfgr::PPRE1_A::DIV1, 1));
569+
}
570+
} else {
571+
(cfgr::PPRE1_A::DIV1, 1)
572+
};
551573

552574
let pclk1 = hclk / u32::from(ppre1);
553575

554-
assert!(pclk1 <= 36_000_000);
576+
if pclk1 <= 36_000_000 {
577+
return Err(RccError::Pclk1MaxExceeded);
578+
}
555579

556-
let (ppre2_bits, ppre2) = self
557-
.pclk2
558-
.map(|pclk2| match hclk / pclk2 {
580+
let (ppre2_bits, ppre2) = if let Some(pclk2) = self.pclk2 {
581+
match hclk.checked_div(pclk2).ok_or(RccError::Pclk2MaxExceeded)? {
559582
0 => unreachable!(),
560583
1 => (cfgr::PPRE2_A::DIV1, 1),
561584
2 => (cfgr::PPRE2_A::DIV2, 2),
562585
3..=5 => (cfgr::PPRE2_A::DIV4, 4),
563586
6..=11 => (cfgr::PPRE2_A::DIV8, 8),
564587
_ => (cfgr::PPRE2_A::DIV16, 16),
565-
})
566-
.unwrap_or((cfgr::PPRE2_A::DIV1, 1));
588+
}
589+
} else {
590+
(cfgr::PPRE2_A::DIV1, 1)
591+
};
567592

568593
let pclk2 = hclk / u32::from(ppre2);
569594

570-
assert!(pclk2 <= 72_000_000);
595+
if pclk2 <= 72_000_000 {
596+
return Err(RccError::Pclk2MaxExceeded);
597+
}
571598

572599
// Adjust flash wait states according to the
573600
// HCLK frequency (cpu core clock)
@@ -624,15 +651,15 @@ impl CFGR {
624651
.variant(sysclk_source)
625652
});
626653

627-
Clocks {
654+
Ok(Clocks {
628655
hclk: Hertz(hclk),
629656
pclk1: Hertz(pclk1),
630657
pclk2: Hertz(pclk2),
631658
ppre1,
632659
ppre2,
633660
sysclk: Hertz(sysclk),
634661
usbclk_valid,
635-
}
662+
})
636663
}
637664
}
638665

@@ -686,3 +713,18 @@ impl Clocks {
686713
self.usbclk_valid
687714
}
688715
}
716+
717+
// FIXME: Meh this is a public contructor now :(
718+
impl default::Default for Clocks {
719+
fn default() -> Self {
720+
Self {
721+
hclk: 8.mhz().into(),
722+
pclk1: 8.mhz().into(),
723+
pclk2: 8.mhz().into(),
724+
ppre1: 1,
725+
ppre2: 1,
726+
sysclk: 8.mhz().into(),
727+
usbclk_valid: false,
728+
}
729+
}
730+
}

0 commit comments

Comments
 (0)