Skip to content

Commit

Permalink
Merge pull request #16 from MabezDev/pll-config
Browse files Browse the repository at this point in the history
RCC/PLL:
  • Loading branch information
MabezDev authored Oct 6, 2018
2 parents f9c7752 + b258828 commit a372a82
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 27 deletions.
88 changes: 88 additions & 0 deletions examples/pll_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Test the serial interface
//!
//! This example requires you to short (connect) the TX and RX pins.
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

extern crate cortex_m;
#[macro_use(entry, exception)]
extern crate cortex_m_rt as rt;
#[macro_use(block)]
extern crate nb;
extern crate panic_semihosting;

extern crate stm32l432xx_hal as hal;
// #[macro_use(block)]
// extern crate nb;

use cortex_m::asm;
use hal::prelude::*;
use hal::serial::Serial;
use hal::stm32l4::stm32l4x2;
use hal::rcc::PllConfig;
use rt::ExceptionFrame;

entry!(main);

fn main() -> ! {
let p = stm32l4x2::Peripherals::take().unwrap();

let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();
let mut gpioa = p.GPIOA.split(&mut rcc.ahb2);
// let mut gpiob = p.GPIOB.split(&mut rcc.ahb2);

// clock configuration using the default settings (all clocks run at 8 MHz)
// let clocks = rcc.cfgr.freeze(&mut flash.acr);
// TRY this alternate clock configuration (clocks run at nearly the maximum frequency)
// let clocks = rcc.cfgr.sysclk(80.mhz()).pclk1(80.mhz()).pclk2(80.mhz()).freeze(&mut flash.acr);
let plls = PllConfig {
m: 0b001, // / 2
n: 0b1000, // * 8
r: 0b11 // /8
};
// NOTE: it is up to the user to make sure the pll config matches the given sysclk
let clocks = rcc.cfgr.sysclk_with_pll(8.mhz(), plls).pclk1(8.mhz()).pclk2(8.mhz()).freeze(&mut flash.acr);

// The Serial API is highly generic
// TRY the commented out, different pin configurations
let tx = gpioa.pa9.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
// let tx = gpiob.pb6.into_af7(&mut gpiob.moder, &mut gpiob.afrl);

let rx = gpioa.pa10.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
// let rx = gpiob.pb7.into_af7(&mut gpiob.moder, &mut gpiob.afrl);

// TRY using a different USART peripheral here
let serial = Serial::usart1(p.USART1, (tx, rx), 9_600.bps(), clocks, &mut rcc.apb2);
let (mut tx, mut rx) = serial.split();

let sent = b'X';

// The `block!` macro makes an operation block until it finishes
// NOTE the error type is `!`

block!(tx.write(sent)).ok();

let received = block!(rx.read()).unwrap();

assert_eq!(received, sent);

// if all goes well you should reach this breakpoint
asm::bkpt();

loop {}
}

exception!(HardFault, hard_fault);

fn hard_fault(ef: &ExceptionFrame) -> ! {
panic!("{:#?}", ef);
}

exception!(*, default_handler);

fn default_handler(irqn: i16) {
panic!("Unhandled exception (IRQn = {})", irqn);
}
77 changes: 50 additions & 27 deletions src/rcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl RccExt for RCC {
pclk1: None,
pclk2: None,
sysclk: None,
pllcfg: None,
},
}
}
Expand Down Expand Up @@ -204,6 +205,7 @@ pub struct CFGR {
pclk1: Option<u32>,
pclk2: Option<u32>,
sysclk: Option<u32>,
pllcfg: Option<PllConfig>
}

impl CFGR {
Expand Down Expand Up @@ -243,17 +245,41 @@ impl CFGR {
self
}

/// Sets the system (core) frequency with some pll configuration
pub fn sysclk_with_pll<F>(mut self, freq: F, cfg: PllConfig) -> Self
where
F: Into<Hertz>,
{
self.pllcfg = Some(cfg);
self.sysclk = Some(freq.into().0);
self
}

/// Freezes the clock configuration, making it effective
pub fn freeze(self, acr: &mut ACR) -> Clocks {
let pllmul = (2 * self.sysclk.unwrap_or(HSI)) / HSI;
let pllmul = cmp::min(cmp::max(pllmul, 2), 16);
let pllmul_bits = if pllmul == 2 {
None

let pllconf = if self.pllcfg.is_none() {
let plln = (2 * self.sysclk.unwrap_or(HSI)) / HSI;
let plln = cmp::min(cmp::max(plln, 2), 16);
if plln == 2 {
None
} else {
// create a best effort pll config, just multiply n
// TODO should we reject this configuration as the clocks stored in RCC could cause timing issues?
let conf = PllConfig {
m: 0b0,
r: 0b0,
n: plln as u8
};
Some(conf)
}

} else {
Some(pllmul as u8) // - 2
let conf = self.pllcfg.unwrap();
Some(conf)
};

let sysclk = pllmul * HSI / 2;
let sysclk = self.sysclk.unwrap_or(HSI);

assert!(sysclk <= 80_000_000);

Expand All @@ -274,7 +300,7 @@ impl CFGR {

let hclk = sysclk / (1 << (hpre_bits));

assert!(hclk <= 80_000_000);
assert!(hclk <= sysclk);

let ppre1_bits = self.pclk1
.map(|pclk1| match hclk / pclk1 {
Expand All @@ -290,21 +316,7 @@ impl CFGR {
let ppre1 = 1 << (ppre1_bits);
let pclk1 = hclk / u32(ppre1);

assert!(pclk1 <= 80_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!(pclk1 <= sysclk);

let ppre2_bits = self.pclk2
.map(|pclk2| match hclk / pclk2 {
Expand All @@ -320,7 +332,7 @@ impl CFGR {
let ppre2 = 1 << (ppre2_bits);
let pclk2 = hclk / u32(ppre2);

assert!(pclk2 <= 80_000_000);
assert!(pclk2 <= sysclk);

// adjust flash wait states
unsafe {
Expand All @@ -337,7 +349,7 @@ impl CFGR {

let rcc = unsafe { &*RCC::ptr() };
let sysclk_src_bits;
if let Some(pllmul_bits) = pllmul_bits {
if let Some(pllconf) = pllconf {
// use PLL as source
sysclk_src_bits = 0b11;
rcc.cr.modify(|_, w| w.pllon().clear_bit());
Expand All @@ -351,9 +363,9 @@ impl CFGR {
.modify(|_, w| unsafe {
w.pllsrc()
.bits(pllsrc_bits)
.pllm().bits(0b0) // no division, how to calculate?
.pllr().bits(0b0) // no division, how to calculate?
.plln().bits(pllmul_bits)
.pllm().bits(pllconf.m)
.pllr().bits(pllconf.r)
.plln().bits(pllconf.n)
});

rcc.cr.modify(|_, w| w.pllon().set_bit());
Expand Down Expand Up @@ -414,6 +426,17 @@ impl CFGR {
}
}

#[derive(Clone, Copy)]
/// Pll Configuration - Calculation = ((SourceClk / m) * n) / r
pub struct PllConfig {
/// Main PLL Division factor
pub m: u8,
/// Main Pll Multiplication factor
pub n: u8,
/// Main PLL division factor for PLLCLK (system clock)
pub r: u8,
}

/// Frozen clock frequencies
///
/// The existence of this value indicates that the clock configuration can no longer be changed
Expand Down

0 comments on commit a372a82

Please sign in to comment.