From 5aca8c815e69d5cd460286fab8acbc0caac6e2df Mon Sep 17 00:00:00 2001 From: jsjolund <j.sjolund@gmail.com> Date: Wed, 13 Dec 2017 11:20:42 +0100 Subject: [PATCH] Add clocking function, fix LED bug --- examples/mco.rs | 67 ++++++++++------------------------ src/capture.rs | 2 +- src/clock.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ src/led.rs | 16 ++++----- src/lib.rs | 1 + 5 files changed, 122 insertions(+), 59 deletions(-) create mode 100644 src/clock.rs diff --git a/examples/mco.rs b/examples/mco.rs index 50da4ec..ecd85c9 100644 --- a/examples/mco.rs +++ b/examples/mco.rs @@ -1,5 +1,5 @@ // #![deny(unsafe_code)] -#![deny(warnings)] +// #![deny(warnings)] #![feature(proc_macro)] #![no_std] @@ -9,75 +9,44 @@ extern crate f4; use rtfm::app; use f4::led::{self, LED}; -use f4::frequency::apb1; +use f4::clock; // TASKS & RESOURCES app! { device: f4::stm32f40x, } -fn clk_init(p: &init::Peripherals) { - // setting up the flash memory latency - // RM0368 8.4.1 (register), 3.4 Table 6 - // we assume 3.3 volt operation, thus 2 cycles for 84mHz - // apb1 will be at 42 MHz - ::apb1::set_frequency(42_000_000); - p.FLASH.acr.modify(|_, w| unsafe { w.latency().bits(2) }); - println!("Flash latency! {:x}", p.FLASH.acr.read().latency().bits()); - - p.RCC - .cfgr - .modify(|_, w| w.sw0().clear_bit().sw1().clear_bit()); //Switch to HSI - p.RCC.cfgr.modify(|_, w| unsafe { w.ppre1().bits(4) }); //Configure apb1 prescaler = 2, - p.RCC.apb1enr.modify(|_, w| w.pwren().set_bit()); - p.RCC.cr.write(|w| w.pllon().clear_bit()); - - //Enable PLL - // PP PLLN PLLM - // 0b0000 0000 0000 00 01 0 101010000 010000 - // RM0368 6.3.2 - // PP 01 - p.RCC - .pllcfgr - .write(|w| unsafe { w.bits(0b00000000000000010101010000010000) }); //Configure PLL - - p.RCC.cr.modify(|_, w| w.pllon().set_bit()); //Enable PLL - - while p.RCC.cr.read().pllrdy().bit_is_clear() {} - - p.RCC - .cfgr - .modify(|_, w| w.sw0().clear_bit().sw1().set_bit()); //Switch to PLL - - // System configuration controller clock enable - p.RCC.apb2enr.modify(|_, w| w.syscfgen().set_bit()); - - p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); //Enable GPIOA clock - p.RCC.ahb1enr.modify(|_, w| w.gpioben().set_bit()); //Enable GPIOB clock -} - // INITIALIZATION PHASE fn init(p: init::Peripherals) { + // RM0368 6.2.10 + // Configure PA8 as MCO_1 alternate function to output HSI clock + p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); //Enable GPIOA clock + p.GPIOA.ospeedr.modify(|_,w| w.ospeedr8().bits(0b11)); //Highest output speed + p.GPIOA.afrh.modify(|_,w| w.afrh8().bits(0)); //Alternate function AF0 MCO_1 on pin 8 + p.GPIOA.moder.modify(|_,w| w.moder8().bits(0b10)); //Alternate function push-pull + p.RCC.cfgr.modify(|_, w| unsafe {w.mco1().bits(0b00)}); //HSI clock selected + p.RCC.cfgr.modify(|_, w| unsafe {w.mco1pre().bits(0)}); //No division - // Configure PC9 as MCO_2 alternate function to output SYSCLK + // Configure PC9 as MCO_2 alternate function to output System clock p.RCC.ahb1enr.modify(|_, w| w.gpiocen().set_bit()); //Enable GPIOC clock p.GPIOC.ospeedr.modify(|_,w| unsafe {w.ospeedr9().bits(0b11)}); //Highest output speed - p.GPIOC.afrh.modify(|_,w| unsafe {w.afrh9().bits(0)}); //Alternate function AF00 MCO_2 on pin 9 + p.GPIOC.afrh.modify(|_,w| unsafe {w.afrh9().bits(0)}); //Alternate function AF0 MCO_2 on pin 9 p.GPIOC.moder.modify(|_,w| unsafe {w.moder9().bits(0b10)}); //Alternate function push-pull - p.RCC.cfgr.modify(|_, w| unsafe {w.mco2().bits(0)}); //MCO2 SYSCLK clock selected - p.RCC.cfgr.modify(|_, w| unsafe {w.mco2pre().bits(0b111)}); //MCO2 SYSCLK clock selected + p.RCC.cfgr.modify(|_, w| unsafe {w.mco2().bits(0b00)}); //MCO2 SYSCLK clock selected + p.RCC.cfgr.modify(|_, w| unsafe {w.mco2pre().bits(0b110)}); //Divide SYSCLK by 4 - clk_init(&p); + let sysclk = clock::set_100_mhz(&p.RCC, &p.FLASH); + println!("SYSCLK set to {}", sysclk); + // PC9 should now output sysclk/4 MHz and PA8 the frequency of the HSI RC led::init(&p.GPIOA, &p.RCC); } // IDLE LOOP fn idle() -> ! { + LED.on(); // Sleep loop { - LED.on(); rtfm::wfi(); - LED.off(); } } diff --git a/src/capture.rs b/src/capture.rs index bba171e..44604d6 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -36,7 +36,7 @@ use core::any::{Any, TypeId}; use core::u32; -use cast::{u16, u32}; +use cast::{u32}; use hal; use nb; use stm32f40x::{TIM1, TIM2, TIM3, TIM4, GPIOA, GPIOB, GPIOC, RCC}; diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..4b58121 --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,95 @@ +//! System clocking + +use stm32f40x::{FLASH, RCC}; + +const HSI_FREQ: u32 = 16_000_000; + +fn calculate_pll(m: u8, n: u16, p: u8) -> (u32, u32) { + // RM0368 6.3.2 + + let pllm_output = match m { + 2...63 => match HSI_FREQ / m as u32 { + 950_000...2_100_000 => HSI_FREQ / m as u32, + _ => panic!("Invalid PLLM output frequency"), + }, + _ => panic!("Invalid PLLM divisor"), + }; + let vco_clock = match n { + 50...432 => match pllm_output * n as u32 { + 100_000_000...432_000_000 => pllm_output * n as u32, + _ => panic!("Invalid PLLN output frequency"), + }, + _ => panic!("Invalid PLLN multiplier"), + }; + let log2p = match p { + 2 => 0b00, + 4 => 0b01, + 6 => 0b10, + 8 => 0b11, + _ => panic!("Invalid PLLP divisor"), + }; + let pll_output = match vco_clock / p as u32 { + 24_000_000...100_000_000 => vco_clock / p as u32, + _ => panic!("Invalid PLLP output frequency"), + }; + let pll_bitmask = ((log2p as u32) << 16) | ((n as u32) << 6) | (m as u32); + + (pll_bitmask, pll_output) +} + + + +/// Set system clock +pub fn set(rcc: &RCC, flash: &FLASH, m: u8, n: u16, p: u8) -> u32 { + let (pll_bitmask, sysclk) = calculate_pll(m, n, p); + // let ahb prescaler = 1, then + let hclk = sysclk; + + // setting up the flash memory latency + // RM0368 8.4.1 (register), 3.4 Table 6 + // apb1 will be at 42 MHz + rcc.cfgr.modify(|_, w| unsafe { w.ppre1().bits(4) }); //Configure apb1 prescaler = 2, + ::apb1::set_frequency(hclk / 2); + + // we assume 3.3 volt operation, thus 2 cycles for 84MHz + flash.acr.modify(|_, w| unsafe { + w.latency().bits(match hclk { + 0...30_000_000 => 0, + 30_000_000...64_000_000 => 1, + 64_000_000...90_000_000 => 2, + 90_000_000...100_000_000 => 3, + _ => panic!("Invalid HCLK frequency"), + }) + }); + // println!("Flash latency! {:x}", p.FLASH.acr.read().latency().bits()); + + rcc.cfgr + .modify(|_, w| w.sw0().clear_bit().sw1().clear_bit()); //Switch to HSI + rcc.apb1enr.modify(|_, w| w.pwren().set_bit()); + rcc.cr.write(|w| w.pllon().clear_bit()); + + //Enable PLL + rcc.pllcfgr.write(|w| unsafe { w.bits(pll_bitmask) }); //Configure PLL + + rcc.cr.modify(|_, w| w.pllon().set_bit()); //Enable PLL + + while rcc.cr.read().pllrdy().bit_is_clear() {} + + rcc.cfgr.modify(|_, w| w.sw0().clear_bit().sw1().set_bit()); //Switch to PLL + + // System configuration controller clock enable + rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit()); + + rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); //Enable GPIOA clock + rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit()); //Enable GPIOB clock + hclk +} + +/// Set system clock to 100 MHz +pub fn set_100_mhz(rcc: &RCC, flash: &FLASH) -> u32 { + set(rcc, flash, 16, 400, 4) +} +/// Set system clock to 84 MHz +pub fn set_84_mhz(rcc: &RCC, flash: &FLASH) -> u32 { + set(rcc, flash, 16, 336, 4) +} diff --git a/src/led.rs b/src/led.rs index 7cc56b9..dc691f0 100644 --- a/src/led.rs +++ b/src/led.rs @@ -1,10 +1,8 @@ -//! User LEDs -//! -//! - PA5 +//! User LED PA5 use stm32f40x::{GPIOA, RCC}; -/// LED connected to pin PC13 +/// LED connected to pin PA5 pub const LED: PA5 = PA5; /// Pin PA5. There's an LED connected to this pin @@ -12,25 +10,25 @@ pub struct PA5; /// Initializes the user LED pub fn init(gpioa: &GPIOA, rcc: &RCC) { - // power on GPIOC + // power on GPIOA rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); - // configure PC13 as output - gpioa.moder.write(|w| w.moder5().bits(1)); + // configure PA5 as output + gpioa.moder.modify(|_,w| w.moder5().bits(1)); } impl PA5 { /// Turns the LED on pub fn on(&self) { unsafe { - (*GPIOA.get()).odr.write(|w| w.odr5().bit(false)); + (*GPIOA.get()).odr.modify(|_,w| w.odr5().bit(true)); } } /// Turns the LED off pub fn off(&self) { unsafe { - (*GPIOA.get()).odr.write(|w| w.odr5().bit(true)); + (*GPIOA.get()).odr.modify(|_,w| w.odr5().bit(false)); } } } diff --git a/src/lib.rs b/src/lib.rs index d46faa0..e8b7554 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ pub mod timer; pub mod time; pub mod pwm; pub mod capture; +pub mod clock; pub mod frequency; use frequency::*; -- GitLab