From e55726964d8852a2b1fa0c3d677588f5abf518b0 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 26 Oct 2021 13:45:53 +0200 Subject: [PATCH] Fix clock setup for MSI and PLL to allow RNG opereation Add RNG example using PLL as clock source. --- embassy-stm32/src/rcc/l4/mod.rs | 147 +++++++++++++++++++++++++++++--- examples/stm32l4/src/bin/rng.rs | 37 ++++++++ 2 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 examples/stm32l4/src/bin/rng.rs diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs index aac0febe2..e1eadf856 100644 --- a/embassy-stm32/src/rcc/l4/mod.rs +++ b/embassy-stm32/src/rcc/l4/mod.rs @@ -1,4 +1,3 @@ -pub use super::types::*; use crate::pac; use crate::peripherals::{self, RCC}; use crate::rcc::{get_freqs, set_freqs, Clocks}; @@ -14,18 +13,116 @@ use stm32_metapac::rcc::vals::Msirange; /// Only the basic setup using the HSE and HSI clocks are supported as of now. -/// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +/// HSI16 speed +pub const HSI16_FREQ: u32 = 16_000_000; /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { - PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul), + PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option), MSI(MSIRange), HSE(Hertz), HSI16, } +/// MSI Clock Range +/// +/// These ranges control the frequency of the MSI. Internally, these ranges map +/// to the `MSIRANGE` bits in the `RCC_ICSCR` register. +#[derive(Clone, Copy)] +pub enum MSIRange { + /// Around 100 kHz + Range0, + /// Around 200 kHz + Range1, + /// Around 400 kHz + Range2, + /// Around 800 kHz + Range3, + /// Around 1 MHz + Range4, + /// Around 2 MHz + Range5, + /// Around 4 MHz (reset value) + Range6, + /// Around 8 MHz + Range7, + /// Around 16 MHz + Range8, + /// Around 24 MHz + Range9, + /// Around 32 MHz + Range10, + /// Around 48 MHz + Range11, +} + +impl Into for MSIRange { + fn into(self) -> u32 { + match self { + MSIRange::Range0 => 100_000, + MSIRange::Range1 => 200_000, + MSIRange::Range2 => 400_000, + MSIRange::Range3 => 800_000, + MSIRange::Range4 => 1_000_000, + MSIRange::Range5 => 2_000_000, + MSIRange::Range6 => 4_000_000, + MSIRange::Range7 => 8_000_000, + MSIRange::Range8 => 16_000_000, + MSIRange::Range9 => 24_000_000, + MSIRange::Range10 => 32_000_000, + MSIRange::Range11 => 48_000_000, + } + } +} + +impl Default for MSIRange { + fn default() -> MSIRange { + MSIRange::Range6 + } +} + +pub type PLL48Div = PLLClkDiv; + +/// PLL divider +#[derive(Clone, Copy)] +pub enum PLLDiv { + Div2, + Div3, + Div4, +} + +/// AHB prescaler +#[derive(Clone, Copy, PartialEq)] +pub enum AHBPrescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, + Div64, + Div128, + Div256, + Div512, +} + +/// APB prescaler +#[derive(Clone, Copy)] +pub enum APBPrescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, +} + +/// PLL clock input source +#[derive(Clone, Copy)] +pub enum PLLSource { + HSI16, + HSE(Hertz), +} + seq_macro::seq!(N in 8..=86 { #[derive(Clone, Copy)] pub enum PLLMul { @@ -134,6 +231,11 @@ impl Into for MSIRange { MSIRange::Range4 => Msirange::RANGE1M, MSIRange::Range5 => Msirange::RANGE2M, MSIRange::Range6 => Msirange::RANGE4M, + MSIRange::Range7 => Msirange::RANGE8M, + MSIRange::Range8 => Msirange::RANGE16M, + MSIRange::Range9 => Msirange::RANGE24M, + MSIRange::Range10 => Msirange::RANGE32M, + MSIRange::Range11 => Msirange::RANGE48M, } } } @@ -177,7 +279,7 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI16, + mux: ClockSrc::MSI(MSIRange::Range6), ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, @@ -249,7 +351,7 @@ impl RccExt for RCC { while !rcc.cr().read().hsirdy() {} } - (HSI_FREQ, 0x01) + (HSI16_FREQ, 0b01) } ClockSrc::HSE(freq) => { // Enable HSE @@ -258,22 +360,30 @@ impl RccExt for RCC { while !rcc.cr().read().hserdy() {} } - (freq.0, 0x02) + (freq.0, 0b10) } ClockSrc::MSI(range) => { // Enable MSI unsafe { rcc.cr().write(|w| { - w.set_msirange(range.into()); + let bits: Msirange = range.into(); + w.set_msirange(bits); + w.set_msipllen(false); + w.set_msirgsel(true); w.set_msion(true); }); while !rcc.cr().read().msirdy() {} - } - let freq = 32_768 * (1 << (range as u8 + 1)); - (freq, 0b00) + // Enable as clock source for USB, RNG if running at 48 MHz + if let MSIRange::Range11 = range { + rcc.ccipr().modify(|w| { + w.set_clk48sel(0b11); + }); + } + } + (range.into(), 0b00) } - ClockSrc::PLL(src, div, prediv, mul) => { + ClockSrc::PLL(src, div, prediv, mul, pll48div) => { let freq = match src { PLLSource::HSE(freq) => { // Enable HSE @@ -289,7 +399,7 @@ impl RccExt for RCC { rcc.cr().write(|w| w.set_hsion(true)); while !rcc.cr().read().hsirdy() {} } - HSI_FREQ + HSI16_FREQ } }; @@ -308,9 +418,20 @@ impl RccExt for RCC { w.set_plln(mul.into()); w.set_pllm(prediv.into()); w.set_pllr(div.into()); + if let Some(pll48div) = pll48div { + w.set_pllq(pll48div.into()); + w.set_pllqen(true); + } w.set_pllsrc(src.into()); }); + // Enable as clock source for USB, RNG if PLL48 divisor is provided + if pll48div.is_some() { + rcc.ccipr().modify(|w| { + w.set_clk48sel(0b10); + }); + } + // Enable PLL rcc.cr().modify(|w| w.set_pllon(true)); while !rcc.cr().read().pllrdy() {} diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs new file mode 100644 index 000000000..ee5f579f8 --- /dev/null +++ b/examples/stm32l4/src/bin/rng.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy::traits::rng::Random; +use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use embassy_stm32::rng::Rng; +use embassy_stm32::{Config, Peripherals}; +use example_common::*; + +fn config() -> Config { + let mut config = Config::default(); + config.rcc = config.rcc.clock_src(ClockSrc::PLL( + PLLSource::HSI16, + PLLClkDiv::Div2, + PLLSrcDiv::Div1, + PLLMul::Mul8, + Some(PLLClkDiv::Div2), + )); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut rng = Random::new(Rng::new(p.RNG)); + + loop { + info!("random {}", unwrap!(rng.next_u8(16).await)); + Timer::after(Duration::from_secs(1)).await; + } +}