123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- use core::cmp;
- use cast::u32;
- use stm32::rcc::cfgr::{SWW, USBPREW};
- use stm32::{rcc, RCC};
- use flash::ACR;
- use time::Hertz;
- /// Extension trait that constrains the `RCC` peripheral
- pub trait RccExt {
- /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
- fn constrain(self) -> Rcc;
- }
- impl RccExt for RCC {
- fn constrain(self) -> Rcc {
- Rcc {
- ahb: AHB { _0: () },
- apb1: APB1 { _0: () },
- apb2: APB2 { _0: () },
- cfgr: CFGR {
- hse: None,
- hclk: None,
- pclk1: None,
- pclk2: None,
- sysclk: None,
- },
- }
- }
- }
- /// Constrained RCC peripheral
- pub struct Rcc {
- /// AMBA High-performance Bus (AHB) registers
- pub ahb: AHB,
- /// Advanced Peripheral Bus 1 (APB1) registers
- pub apb1: APB1,
- /// Advanced Peripheral Bus 2 (APB2) registers
- pub apb2: APB2,
- pub cfgr: CFGR,
- }
- /// AMBA High-performance Bus (AHB) registers
- pub struct AHB {
- _0: (),
- }
- impl AHB {
- pub(crate) fn enr(&mut self) -> &rcc::AHBENR {
- // NOTE(unsafe) this proxy grants exclusive access to this register
- unsafe { &(*RCC::ptr()).ahbenr }
- }
- }
- /// Advanced Peripheral Bus 1 (APB1) registers
- pub struct APB1 {
- _0: (),
- }
- impl APB1 {
- pub(crate) fn enr(&mut self) -> &rcc::APB1ENR {
- // NOTE(unsafe) this proxy grants exclusive access to this register
- unsafe { &(*RCC::ptr()).apb1enr }
- }
- pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR {
- // NOTE(unsafe) this proxy grants exclusive access to this register
- unsafe { &(*RCC::ptr()).apb1rstr }
- }
- }
- /// Advanced Peripheral Bus 2 (APB2) registers
- pub struct APB2 {
- _0: (),
- }
- impl APB2 {
- pub(crate) fn enr(&mut self) -> &rcc::APB2ENR {
- // NOTE(unsafe) this proxy grants exclusive access to this register
- unsafe { &(*RCC::ptr()).apb2enr }
- }
- pub(crate) fn rstr(&mut self) -> &rcc::APB2RSTR {
- // NOTE(unsafe) this proxy grants exclusive access to this register
- unsafe { &(*RCC::ptr()).apb2rstr }
- }
- }
- const HSI: u32 = 8_000_000; // Hz
- pub struct CFGR {
- hse: Option<u32>,
- hclk: Option<u32>,
- pclk1: Option<u32>,
- pclk2: Option<u32>,
- sysclk: Option<u32>,
- }
- impl CFGR {
- /// Uses HSE (external oscillator) instead of HSI (internal RC oscillator) as the clock source.
- /// Will result in a hang if an external oscillator is not connected or it fails to start.
- pub fn use_hse<F>(mut self, freq: F) -> Self
- where
- F: Into<Hertz>,
- {
- self.hse = Some(freq.into().0);
- self
- }
- /// Sets the desired frequency for the HCLK clock
- pub fn hclk<F>(mut self, freq: F) -> Self
- where
- F: Into<Hertz>,
- {
- self.hclk = Some(freq.into().0);
- self
- }
- /// Sets the desired frequency for the PCKL1 clock
- pub fn pclk1<F>(mut self, freq: F) -> Self
- where
- F: Into<Hertz>,
- {
- self.pclk1 = Some(freq.into().0);
- self
- }
- /// Sets the desired frequency for the PCLK2 clock
- pub fn pclk2<F>(mut self, freq: F) -> Self
- where
- F: Into<Hertz>,
- {
- self.pclk2 = Some(freq.into().0);
- self
- }
- /// Sets the desired frequency for the SYSCLK clock
- pub fn sysclk<F>(mut self, freq: F) -> Self
- where
- F: Into<Hertz>,
- {
- self.sysclk = Some(freq.into().0);
- self
- }
- pub fn freeze(self, acr: &mut ACR) -> Clocks {
- // TODO ADC clock
- let pllsrcclk = self.hse.unwrap_or(HSI / 2);
- let pllmul = self.sysclk.unwrap_or(pllsrcclk) / pllsrcclk;
- let pllmul = cmp::min(cmp::max(pllmul, 1), 16);
- let (pllmul_bits, sysclk) = if pllmul == 1 {
- (None, self.hse.unwrap_or(HSI))
- } else {
- (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
- };
- assert!(sysclk <= 72_000_000);
- let hpre_bits = self.hclk
- .map(|hclk| match sysclk / hclk {
- 0 => unreachable!(),
- 1 => 0b0111,
- 2 => 0b1000,
- 3...5 => 0b1001,
- 6...11 => 0b1010,
- 12...39 => 0b1011,
- 40...95 => 0b1100,
- 96...191 => 0b1101,
- 192...383 => 0b1110,
- _ => 0b1111,
- })
- .unwrap_or(0b0111);
- let hclk = sysclk / (1 << (hpre_bits - 0b0111));
- assert!(hclk <= 72_000_000);
- let ppre1_bits = self.pclk1
- .map(|pclk1| match hclk / pclk1 {
- 0 => unreachable!(),
- 1 => 0b011,
- 2 => 0b100,
- 3...5 => 0b101,
- 6...11 => 0b110,
- _ => 0b111,
- })
- .unwrap_or(0b011);
- let ppre1 = 1 << (ppre1_bits - 0b011);
- let pclk1 = hclk / u32(ppre1);
- assert!(pclk1 <= 36_000_000);
- let ppre2_bits = self.pclk2
- .map(|pclk2| match hclk / pclk2 {
- 0 => unreachable!(),
- 1 => 0b011,
- 2 => 0b100,
- 3...5 => 0b101,
- 6...11 => 0b110,
- _ => 0b111,
- })
- .unwrap_or(0b011);
- let ppre2 = 1 << (ppre2_bits - 0b011);
- let pclk2 = hclk / u32(ppre2);
- assert!(pclk2 <= 72_000_000);
- // adjust flash wait states
- unsafe {
- acr.acr().write(|w| {
- w.latency().bits(if sysclk <= 24_000_000 {
- 0b000
- } else if sysclk <= 48_000_000 {
- 0b001
- } else {
- 0b010
- })
- })
- }
- // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
- // PLL output frequency is a supported one.
- let (usbpre, usbclk_valid) = match (self.hse, pllmul_bits, sysclk) {
- (Some(_), Some(_), 72_000_000) => (USBPREW::DIV15, true),
- (Some(_), Some(_), 48_000_000) => (USBPREW::NODIV, true),
- _ => (USBPREW::NODIV, false),
- };
- let rcc = unsafe { &*RCC::ptr() };
- if self.hse.is_some() {
- // enable HSE and wait for it to be ready
- rcc.cr.modify(|_, w| w.hseon().set_bit());
- while rcc.cr.read().hserdy().bit_is_clear() {}
- }
- if let Some(pllmul_bits) = pllmul_bits {
- // enable PLL and wait for it to be ready
- rcc.cfgr.modify(|_, w| unsafe {
- w.pllmul()
- .bits(pllmul_bits)
- .pllsrc()
- .bit(if self.hse.is_some() {
- true
- } else {
- false
- })
- });
- rcc.cr.modify(|_, w| w.pllon().set_bit());
- while rcc.cr.read().pllrdy().bit_is_clear() {}
- }
- // set prescalers and clock source
- rcc.cfgr.modify(|_, w| unsafe {
- w.ppre2()
- .bits(ppre2_bits)
- .ppre1()
- .bits(ppre1_bits)
- .hpre()
- .bits(hpre_bits)
- .usbpre()
- .variant(usbpre)
- .sw()
- .variant(if pllmul_bits.is_some() {
- SWW::PLL
- } else if self.hse.is_some() {
- SWW::HSE
- } else {
- SWW::HSI
- })
- });
- Clocks {
- hclk: Hertz(hclk),
- pclk1: Hertz(pclk1),
- pclk2: Hertz(pclk2),
- ppre1,
- ppre2,
- sysclk: Hertz(sysclk),
- usbclk_valid,
- }
- }
- }
- /// Frozen clock frequencies
- ///
- /// The existence of this value indicates that the clock configuration can no longer be changed
- #[derive(Clone, Copy)]
- pub struct Clocks {
- hclk: Hertz,
- pclk1: Hertz,
- pclk2: Hertz,
- ppre1: u8,
- ppre2: u8,
- sysclk: Hertz,
- usbclk_valid: bool,
- }
- impl Clocks {
- /// Returns the frequency of the AHB
- pub fn hclk(&self) -> Hertz {
- self.hclk
- }
- /// Returns the frequency of the APB1
- pub fn pclk1(&self) -> Hertz {
- self.pclk1
- }
- /// Returns the frequency of the APB2
- pub fn pclk2(&self) -> Hertz {
- self.pclk2
- }
- pub(crate) fn ppre1(&self) -> u8 {
- self.ppre1
- }
- // TODO remove `allow`
- #[allow(dead_code)]
- pub(crate) fn ppre2(&self) -> u8 {
- self.ppre2
- }
- /// Returns the system (core) frequency
- pub fn sysclk(&self) -> Hertz {
- self.sysclk
- }
- /// Returns whether the USBCLK clock frequency is valid for the USB peripheral
- pub fn usbclk_valid(&self) -> bool {
- self.usbclk_valid
- }
- }
|