diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f3.rs | 609 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mco.rs | 24 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/hello.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/usb_serial.rs | 21 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/adc.rs | 24 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/hello.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/opamp.rs | 24 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/pwm.rs | 27 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 18 |
10 files changed, 350 insertions, 411 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3f5f12f06..24af17327 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -68,7 +68,7 @@ rand_core = "0.6.3" | |||
| 68 | sdio-host = "0.5.0" | 68 | sdio-host = "0.5.0" |
| 69 | critical-section = "1.1" | 69 | critical-section = "1.1" |
| 70 | #stm32-metapac = { version = "15" } | 70 | #stm32-metapac = { version = "15" } |
| 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" } | 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82" } |
| 72 | vcell = "0.1.3" | 72 | vcell = "0.1.3" |
| 73 | bxcan = "0.7.0" | 73 | bxcan = "0.7.0" |
| 74 | nb = "1.0.0" | 74 | nb = "1.0.0" |
| @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 89 | proc-macro2 = "1.0.36" | 89 | proc-macro2 = "1.0.36" |
| 90 | quote = "1.0.15" | 90 | quote = "1.0.15" |
| 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 92 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76", default-features = false, features = ["metadata"]} | 92 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82", default-features = false, features = ["metadata"]} |
| 93 | 93 | ||
| 94 | 94 | ||
| 95 | [features] | 95 | [features] |
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 25866e446..0a5e67b4a 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs | |||
| @@ -1,208 +1,230 @@ | |||
| 1 | #[cfg(rcc_f3)] | ||
| 2 | use crate::pac::adccommon::vals::Ckmode; | ||
| 3 | use crate::pac::flash::vals::Latency; | 1 | use crate::pac::flash::vals::Latency; |
| 4 | pub use crate::pac::rcc::vals::Adcpres; | 2 | pub use crate::pac::rcc::vals::{ |
| 5 | use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; | 3 | Adcpres as AdcPllPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, |
| 4 | Sw as Sysclk, | ||
| 5 | }; | ||
| 6 | use crate::pac::rcc::vals::{Pllsrc, Usbpre}; | ||
| 6 | use crate::pac::{FLASH, RCC}; | 7 | use crate::pac::{FLASH, RCC}; |
| 7 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 8 | 9 | ||
| 9 | /// HSI speed | 10 | /// HSI speed |
| 10 | pub const HSI_FREQ: Hertz = Hertz(8_000_000); | 11 | pub const HSI_FREQ: Hertz = Hertz(8_000_000); |
| 11 | 12 | ||
| 12 | #[cfg(rcc_f3)] | 13 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 13 | impl From<AdcClockSource> for Ckmode { | 14 | pub enum HseMode { |
| 14 | fn from(value: AdcClockSource) -> Self { | 15 | /// crystal/ceramic oscillator (HSEBYP=0) |
| 15 | match value { | 16 | Oscillator, |
| 16 | AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, | 17 | /// external analog clock (low swing) (HSEBYP=1) |
| 17 | AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, | 18 | Bypass, |
| 18 | AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, | 19 | } |
| 19 | _ => unreachable!(), | 20 | |
| 20 | } | 21 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 21 | } | 22 | pub struct Hse { |
| 23 | /// HSE frequency. | ||
| 24 | pub freq: Hertz, | ||
| 25 | /// HSE mode. | ||
| 26 | pub mode: HseMode, | ||
| 27 | } | ||
| 28 | |||
| 29 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 30 | pub enum PllSource { | ||
| 31 | HSE, | ||
| 32 | HSI, | ||
| 33 | } | ||
| 34 | |||
| 35 | #[derive(Clone, Copy)] | ||
| 36 | pub struct Pll { | ||
| 37 | pub src: PllSource, | ||
| 38 | |||
| 39 | /// PLL pre-divider. | ||
| 40 | /// | ||
| 41 | /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. | ||
| 42 | pub prediv: PllPreDiv, | ||
| 43 | |||
| 44 | /// PLL multiplication factor. | ||
| 45 | pub mul: PllMul, | ||
| 22 | } | 46 | } |
| 23 | 47 | ||
| 24 | #[derive(Clone, Copy)] | 48 | #[derive(Clone, Copy)] |
| 25 | pub enum AdcClockSource { | 49 | pub enum AdcClockSource { |
| 26 | Pll(Adcpres), | 50 | Pll(AdcPllPrescaler), |
| 27 | BusDiv1, | 51 | Hclk(AdcHclkPrescaler), |
| 28 | BusDiv2, | ||
| 29 | BusDiv4, | ||
| 30 | } | 52 | } |
| 31 | 53 | ||
| 32 | impl AdcClockSource { | 54 | #[derive(Clone, Copy, PartialEq, Eq)] |
| 33 | pub fn bus_div(&self) -> u32 { | 55 | pub enum AdcHclkPrescaler { |
| 34 | match self { | 56 | Div1, |
| 35 | Self::BusDiv1 => 1, | 57 | Div2, |
| 36 | Self::BusDiv2 => 2, | 58 | Div4, |
| 37 | Self::BusDiv4 => 4, | ||
| 38 | _ => unreachable!(), | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | 59 | } |
| 42 | 60 | ||
| 43 | #[derive(Default)] | 61 | #[derive(Clone, Copy, PartialEq, Eq)] |
| 44 | pub enum HrtimClockSource { | 62 | pub enum HrtimClockSource { |
| 45 | #[default] | ||
| 46 | BusClk, | 63 | BusClk, |
| 47 | PllClk, | 64 | PllClk, |
| 48 | } | 65 | } |
| 49 | 66 | ||
| 50 | /// Clocks configutation | 67 | /// Clocks configutation |
| 51 | #[non_exhaustive] | 68 | #[non_exhaustive] |
| 52 | #[derive(Default)] | ||
| 53 | pub struct Config { | 69 | pub struct Config { |
| 54 | /// Frequency of HSE oscillator | 70 | pub hsi: bool, |
| 55 | /// 4MHz to 32MHz | 71 | pub hse: Option<Hse>, |
| 56 | pub hse: Option<Hertz>, | 72 | pub sys: Sysclk, |
| 57 | /// Bypass HSE for an external clock | 73 | |
| 58 | pub bypass_hse: bool, | 74 | pub pll: Option<Pll>, |
| 59 | /// Frequency of the System Clock | 75 | |
| 60 | pub sysclk: Option<Hertz>, | 76 | pub ahb_pre: AHBPrescaler, |
| 61 | /// Frequency of AHB bus | 77 | pub apb1_pre: APBPrescaler, |
| 62 | pub hclk: Option<Hertz>, | 78 | pub apb2_pre: APBPrescaler, |
| 63 | /// Frequency of APB1 bus | 79 | |
| 64 | /// - Max frequency 36MHz | 80 | #[cfg(not(rcc_f37))] |
| 65 | pub pclk1: Option<Hertz>, | 81 | pub adc: AdcClockSource, |
| 66 | /// Frequency of APB2 bus | 82 | #[cfg(all(not(rcc_f37), adc3_common))] |
| 67 | /// - Max frequency with HSE is 72MHz | 83 | pub adc34: AdcClockSource, |
| 68 | /// - Max frequency without HSE is 64MHz | ||
| 69 | pub pclk2: Option<Hertz>, | ||
| 70 | /// USB clock setup | ||
| 71 | /// It is valid only when, | ||
| 72 | /// - HSE is enabled, | ||
| 73 | /// - The System clock frequency is either 48MHz or 72MHz | ||
| 74 | /// - APB1 clock has a minimum frequency of 10MHz | ||
| 75 | pub pll48: bool, | ||
| 76 | #[cfg(rcc_f3)] | ||
| 77 | /// ADC clock setup | ||
| 78 | /// - For AHB, a psc of 4 or less must be used | ||
| 79 | pub adc: Option<AdcClockSource>, | ||
| 80 | #[cfg(rcc_f3)] | ||
| 81 | /// ADC clock setup | ||
| 82 | /// - For AHB, a psc of 4 or less must be used | ||
| 83 | pub adc34: Option<AdcClockSource>, | ||
| 84 | #[cfg(stm32f334)] | 84 | #[cfg(stm32f334)] |
| 85 | pub hrtim: HrtimClockSource, | 85 | pub hrtim: HrtimClockSource, |
| 86 | |||
| 86 | pub ls: super::LsConfig, | 87 | pub ls: super::LsConfig, |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | // Information required to setup the PLL clock | 90 | impl Default for Config { |
| 90 | #[derive(Clone, Copy)] | 91 | fn default() -> Self { |
| 91 | struct PllConfig { | 92 | Self { |
| 92 | pll_src: Pllsrc, | 93 | hsi: true, |
| 93 | pll_mul: Pllmul, | 94 | hse: None, |
| 94 | pll_div: Option<Prediv>, | 95 | sys: Sysclk::HSI, |
| 96 | pll: None, | ||
| 97 | ahb_pre: AHBPrescaler::DIV1, | ||
| 98 | apb1_pre: APBPrescaler::DIV1, | ||
| 99 | apb2_pre: APBPrescaler::DIV1, | ||
| 100 | ls: Default::default(), | ||
| 101 | |||
| 102 | #[cfg(not(rcc_f37))] | ||
| 103 | adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), | ||
| 104 | #[cfg(all(not(rcc_f37), adc3_common))] | ||
| 105 | adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), | ||
| 106 | #[cfg(stm32f334)] | ||
| 107 | hrtim: HrtimClockSource::BusClk, | ||
| 108 | } | ||
| 109 | } | ||
| 95 | } | 110 | } |
| 96 | 111 | ||
| 97 | /// Initialize and Set the clock frequencies | 112 | /// Initialize and Set the clock frequencies |
| 98 | pub(crate) unsafe fn init(config: Config) { | 113 | pub(crate) unsafe fn init(config: Config) { |
| 99 | // Calculate the real System clock, and PLL configuration if applicable | 114 | // Configure HSI |
| 100 | let (sysclk, pll_config) = get_sysclk(&config); | 115 | let hsi = match config.hsi { |
| 101 | assert!(sysclk.0 <= 72_000_000); | 116 | false => { |
| 102 | 117 | RCC.cr().modify(|w| w.set_hsion(false)); | |
| 103 | // Calculate real AHB clock | 118 | None |
| 104 | let hclk = config.hclk.map(|h| h).unwrap_or(sysclk); | 119 | } |
| 105 | let hpre = match sysclk.0 / hclk.0 { | 120 | true => { |
| 106 | 0 => unreachable!(), | 121 | RCC.cr().modify(|w| w.set_hsion(true)); |
| 107 | 1 => Hpre::DIV1, | 122 | while !RCC.cr().read().hsirdy() {} |
| 108 | 2 => Hpre::DIV2, | 123 | Some(HSI_FREQ) |
| 109 | 3..=5 => Hpre::DIV4, | 124 | } |
| 110 | 6..=11 => Hpre::DIV8, | ||
| 111 | 12..=39 => Hpre::DIV16, | ||
| 112 | 40..=95 => Hpre::DIV64, | ||
| 113 | 96..=191 => Hpre::DIV128, | ||
| 114 | 192..=383 => Hpre::DIV256, | ||
| 115 | _ => Hpre::DIV512, | ||
| 116 | }; | ||
| 117 | let hclk = sysclk / hpre; | ||
| 118 | assert!(hclk <= Hertz(72_000_000)); | ||
| 119 | |||
| 120 | // Calculate real APB1 clock | ||
| 121 | let pclk1 = config.pclk1.unwrap_or(hclk); | ||
| 122 | let ppre1 = match hclk / pclk1 { | ||
| 123 | 0 => unreachable!(), | ||
| 124 | 1 => Ppre::DIV1, | ||
| 125 | 2 => Ppre::DIV2, | ||
| 126 | 3..=5 => Ppre::DIV4, | ||
| 127 | 6..=11 => Ppre::DIV8, | ||
| 128 | _ => Ppre::DIV16, | ||
| 129 | }; | ||
| 130 | let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 }; | ||
| 131 | let pclk1 = hclk / ppre1; | ||
| 132 | assert!(pclk1 <= Hertz(36_000_000)); | ||
| 133 | |||
| 134 | // Calculate real APB2 clock | ||
| 135 | let pclk2 = config.pclk2.unwrap_or(hclk); | ||
| 136 | let ppre2 = match hclk / pclk2 { | ||
| 137 | 0 => unreachable!(), | ||
| 138 | 1 => Ppre::DIV1, | ||
| 139 | 2 => Ppre::DIV2, | ||
| 140 | 3..=5 => Ppre::DIV4, | ||
| 141 | 6..=11 => Ppre::DIV8, | ||
| 142 | _ => Ppre::DIV16, | ||
| 143 | }; | 125 | }; |
| 144 | let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 }; | ||
| 145 | let pclk2 = hclk / ppre2; | ||
| 146 | assert!(pclk2 <= Hertz(72_000_000)); | ||
| 147 | 126 | ||
| 148 | // Set latency based on HCLK frquency | 127 | // Configure HSE |
| 149 | // RM0316: "The prefetch buffer must be kept on when using a prescaler | 128 | let hse = match config.hse { |
| 150 | // different from 1 on the AHB clock.", "Half-cycle access cannot be | 129 | None => { |
| 151 | // used when there is a prescaler different from 1 on the AHB clock" | 130 | RCC.cr().modify(|w| w.set_hseon(false)); |
| 152 | FLASH.acr().modify(|w| { | 131 | None |
| 153 | w.set_latency(if hclk <= Hertz(24_000_000) { | ||
| 154 | Latency::WS0 | ||
| 155 | } else if hclk <= Hertz(48_000_000) { | ||
| 156 | Latency::WS1 | ||
| 157 | } else { | ||
| 158 | Latency::WS2 | ||
| 159 | }); | ||
| 160 | if hpre != Hpre::DIV1 { | ||
| 161 | w.set_hlfcya(false); | ||
| 162 | w.set_prftbe(true); | ||
| 163 | } | 132 | } |
| 164 | }); | 133 | Some(hse) => { |
| 134 | match hse.mode { | ||
| 135 | HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), | ||
| 136 | HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), | ||
| 137 | } | ||
| 165 | 138 | ||
| 166 | // Enable HSE | 139 | RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); |
| 167 | // RM0316: "Bits 31:26 Reserved, must be kept at reset value." | 140 | RCC.cr().modify(|w| w.set_hseon(true)); |
| 168 | if config.hse.is_some() { | 141 | while !RCC.cr().read().hserdy() {} |
| 169 | RCC.cr().modify(|w| { | 142 | Some(hse.freq) |
| 170 | w.set_hsebyp(config.bypass_hse); | 143 | } |
| 171 | // We turn on clock security to switch to HSI when HSE fails | 144 | }; |
| 172 | w.set_csson(true); | ||
| 173 | w.set_hseon(true); | ||
| 174 | }); | ||
| 175 | while !RCC.cr().read().hserdy() {} | ||
| 176 | } | ||
| 177 | 145 | ||
| 178 | // Enable PLL | 146 | // Enable PLL |
| 179 | // RM0316: "Reserved, must be kept at reset value." | 147 | // RM0316: "Reserved, must be kept at reset value." |
| 180 | if let Some(ref pll_config) = pll_config { | 148 | let pll = config.pll.map(|pll| { |
| 149 | let (src_val, src_freq) = match pll.src { | ||
| 150 | #[cfg(rcc_f3v3)] | ||
| 151 | PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), | ||
| 152 | #[cfg(not(rcc_f3v3))] | ||
| 153 | PllSource::HSI => { | ||
| 154 | if pll.prediv != PllPreDiv::DIV2 { | ||
| 155 | panic!("if PLL source is HSI, PLL prediv must be 2."); | ||
| 156 | } | ||
| 157 | (Pllsrc::HSI_DIV2, unwrap!(hsi)) | ||
| 158 | } | ||
| 159 | PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), | ||
| 160 | }; | ||
| 161 | let in_freq = src_freq / pll.prediv; | ||
| 162 | assert!(max::PLL_IN.contains(&in_freq)); | ||
| 163 | let out_freq = in_freq * pll.mul; | ||
| 164 | assert!(max::PLL_OUT.contains(&out_freq)); | ||
| 165 | |||
| 166 | RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); | ||
| 181 | RCC.cfgr().modify(|w| { | 167 | RCC.cfgr().modify(|w| { |
| 182 | w.set_pllmul(pll_config.pll_mul); | 168 | w.set_pllmul(pll.mul); |
| 183 | w.set_pllsrc(pll_config.pll_src); | 169 | w.set_pllsrc(src_val); |
| 184 | }); | 170 | }); |
| 185 | if let Some(pll_div) = pll_config.pll_div { | ||
| 186 | RCC.cfgr2().modify(|w| w.set_prediv(pll_div)); | ||
| 187 | } | ||
| 188 | RCC.cr().modify(|w| w.set_pllon(true)); | 171 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 189 | while !RCC.cr().read().pllrdy() {} | 172 | while !RCC.cr().read().pllrdy() {} |
| 190 | } | ||
| 191 | 173 | ||
| 192 | // CFGR has been written before (PLL) don't overwrite these settings | 174 | out_freq |
| 193 | if config.pll48 { | 175 | }); |
| 194 | let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config); | 176 | |
| 195 | RCC.cfgr().modify(|w| { | 177 | let usb = match pll { |
| 196 | w.set_usbpre(usb_pre); | 178 | Some(Hertz(72_000_000)) => { |
| 197 | }); | 179 | RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); |
| 198 | } | 180 | Some(Hertz(48_000_000)) |
| 181 | } | ||
| 182 | Some(Hertz(48_000_000)) => { | ||
| 183 | RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); | ||
| 184 | Some(Hertz(48_000_000)) | ||
| 185 | } | ||
| 186 | _ => None, | ||
| 187 | }; | ||
| 188 | |||
| 189 | // Configure sysclk | ||
| 190 | let sys = match config.sys { | ||
| 191 | Sysclk::HSI => unwrap!(hsi), | ||
| 192 | Sysclk::HSE => unwrap!(hse), | ||
| 193 | Sysclk::PLL1_P => unwrap!(pll), | ||
| 194 | _ => unreachable!(), | ||
| 195 | }; | ||
| 196 | |||
| 197 | let hclk = sys / config.ahb_pre; | ||
| 198 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); | ||
| 199 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); | ||
| 200 | |||
| 201 | assert!(max::HCLK.contains(&hclk)); | ||
| 202 | assert!(max::PCLK1.contains(&pclk1)); | ||
| 203 | assert!(max::PCLK2.contains(&pclk2)); | ||
| 204 | |||
| 205 | // Set latency based on HCLK frquency | ||
| 206 | let latency = match hclk.0 { | ||
| 207 | ..=24_000_000 => Latency::WS0, | ||
| 208 | ..=48_000_000 => Latency::WS1, | ||
| 209 | _ => Latency::WS2, | ||
| 210 | }; | ||
| 211 | FLASH.acr().modify(|w| { | ||
| 212 | w.set_latency(latency); | ||
| 213 | // RM0316: "The prefetch buffer must be kept on when using a prescaler | ||
| 214 | // different from 1 on the AHB clock.", "Half-cycle access cannot be | ||
| 215 | // used when there is a prescaler different from 1 on the AHB clock" | ||
| 216 | if config.ahb_pre != AHBPrescaler::DIV1 { | ||
| 217 | w.set_hlfcya(false); | ||
| 218 | w.set_prftbe(true); | ||
| 219 | } | ||
| 220 | }); | ||
| 199 | 221 | ||
| 200 | // Set prescalers | 222 | // Set prescalers |
| 201 | // CFGR has been written before (PLL, PLL48) don't overwrite these settings | 223 | // CFGR has been written before (PLL, PLL48) don't overwrite these settings |
| 202 | RCC.cfgr().modify(|w| { | 224 | RCC.cfgr().modify(|w| { |
| 203 | w.set_ppre2(ppre2); | 225 | w.set_ppre2(config.apb1_pre); |
| 204 | w.set_ppre1(ppre1); | 226 | w.set_ppre1(config.apb2_pre); |
| 205 | w.set_hpre(hpre); | 227 | w.set_hpre(config.ahb_pre); |
| 206 | }); | 228 | }); |
| 207 | 229 | ||
| 208 | // Wait for the new prescalers to kick in | 230 | // Wait for the new prescalers to kick in |
| @@ -211,53 +233,60 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 211 | cortex_m::asm::delay(16); | 233 | cortex_m::asm::delay(16); |
| 212 | 234 | ||
| 213 | // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings | 235 | // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings |
| 214 | RCC.cfgr().modify(|w| { | 236 | RCC.cfgr().modify(|w| w.set_sw(config.sys)); |
| 215 | w.set_sw(match (pll_config, config.hse) { | ||
| 216 | (Some(_), _) => Sw::PLL1_P, | ||
| 217 | (None, Some(_)) => Sw::HSE, | ||
| 218 | (None, None) => Sw::HSI, | ||
| 219 | }) | ||
| 220 | }); | ||
| 221 | 237 | ||
| 222 | #[cfg(rcc_f3)] | 238 | let rtc = config.ls.init(); |
| 223 | let adc = config.adc.map(|adc| match adc { | 239 | |
| 240 | #[cfg(not(rcc_f37))] | ||
| 241 | use crate::pac::adccommon::vals::Ckmode; | ||
| 242 | |||
| 243 | #[cfg(not(rcc_f37))] | ||
| 244 | let adc = match config.adc { | ||
| 224 | AdcClockSource::Pll(adcpres) => { | 245 | AdcClockSource::Pll(adcpres) => { |
| 225 | RCC.cfgr2().modify(|w| { | 246 | RCC.cfgr2().modify(|w| w.set_adc12pres(adcpres)); |
| 226 | // Make sure that we're using the PLL | 247 | crate::pac::ADC_COMMON |
| 227 | pll_config.unwrap(); | 248 | .ccr() |
| 228 | w.set_adc12pres(adcpres); | 249 | .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); |
| 229 | 250 | ||
| 230 | sysclk / adcpres | 251 | unwrap!(pll) / adcpres |
| 231 | }) | ||
| 232 | } | 252 | } |
| 233 | _ => crate::pac::ADC_COMMON.ccr().modify(|w| { | 253 | AdcClockSource::Hclk(adcpres) => { |
| 234 | assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); | 254 | assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); |
| 235 | 255 | ||
| 236 | w.set_ckmode(adc.into()); | 256 | let (div, ckmode) = match adcpres { |
| 257 | AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), | ||
| 258 | AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), | ||
| 259 | AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), | ||
| 260 | }; | ||
| 261 | crate::pac::ADC_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); | ||
| 237 | 262 | ||
| 238 | sysclk / adc.bus_div() | 263 | hclk / div |
| 239 | }), | 264 | } |
| 240 | }); | 265 | }; |
| 241 | 266 | ||
| 242 | #[cfg(all(rcc_f3, adc3_common))] | 267 | #[cfg(all(not(rcc_f37), adc3_common))] |
| 243 | let adc34 = config.adc34.map(|adc| match adc { | 268 | let adc34 = match config.adc34 { |
| 244 | AdcClockSource::Pll(adcpres) => { | 269 | AdcClockSource::Pll(adcpres) => { |
| 245 | RCC.cfgr2().modify(|w| { | 270 | RCC.cfgr2().modify(|w| w.set_adc34pres(adcpres)); |
| 246 | // Make sure that we're using the PLL | 271 | crate::pac::ADC3_COMMON |
| 247 | pll_config.unwrap(); | 272 | .ccr() |
| 248 | w.set_adc34pres(adcpres); | 273 | .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); |
| 249 | 274 | ||
| 250 | sysclk / adcpres | 275 | unwrap!(pll) / adcpres |
| 251 | }) | ||
| 252 | } | 276 | } |
| 253 | _ => crate::pac::ADC_COMMON.ccr().modify(|w| { | 277 | AdcClockSource::Hclk(adcpres) => { |
| 254 | assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); | 278 | assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); |
| 255 | 279 | ||
| 256 | w.set_ckmode(adc.into()); | 280 | let (div, ckmode) = match adcpres { |
| 281 | AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), | ||
| 282 | AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), | ||
| 283 | AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), | ||
| 284 | }; | ||
| 285 | crate::pac::ADC3_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); | ||
| 257 | 286 | ||
| 258 | sysclk / adc.bus_div() | 287 | hclk / div |
| 259 | }), | 288 | } |
| 260 | }); | 289 | }; |
| 261 | 290 | ||
| 262 | #[cfg(stm32f334)] | 291 | #[cfg(stm32f334)] |
| 263 | let hrtim = match config.hrtim { | 292 | let hrtim = match config.hrtim { |
| @@ -267,195 +296,49 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 267 | use crate::pac::rcc::vals::Timsw; | 296 | use crate::pac::rcc::vals::Timsw; |
| 268 | 297 | ||
| 269 | // Make sure that we're using the PLL | 298 | // Make sure that we're using the PLL |
| 270 | pll_config.unwrap(); | 299 | let pll = unwrap!(pll); |
| 271 | assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk)); | 300 | assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); |
| 272 | 301 | ||
| 273 | RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P)); | 302 | RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P)); |
| 274 | 303 | ||
| 275 | Some(sysclk * 2u32) | 304 | Some(pll * 2u32) |
| 276 | } | 305 | } |
| 277 | }; | 306 | }; |
| 278 | 307 | ||
| 279 | let rtc = config.ls.init(); | ||
| 280 | |||
| 281 | set_clocks!( | 308 | set_clocks!( |
| 282 | hsi: None, | 309 | hsi: hsi, |
| 283 | lse: None, | 310 | hse: hse, |
| 284 | pll1_p: None, | 311 | pll1_p: pll, |
| 285 | sys: Some(sysclk), | 312 | sys: Some(sys), |
| 286 | pclk1: Some(pclk1), | 313 | pclk1: Some(pclk1), |
| 287 | pclk2: Some(pclk2), | 314 | pclk2: Some(pclk2), |
| 288 | pclk1_tim: Some(pclk1 * timer_mul1), | 315 | pclk1_tim: Some(pclk1_tim), |
| 289 | pclk2_tim: Some(pclk2 * timer_mul2), | 316 | pclk2_tim: Some(pclk2_tim), |
| 290 | hclk1: Some(hclk), | 317 | hclk1: Some(hclk), |
| 291 | #[cfg(rcc_f3)] | 318 | #[cfg(not(rcc_f37))] |
| 292 | adc: adc, | 319 | adc: Some(adc), |
| 293 | #[cfg(all(rcc_f3, adc3_common))] | 320 | #[cfg(all(not(rcc_f37), adc3_common))] |
| 294 | adc34: adc34, | 321 | adc34: Some(adc34), |
| 295 | #[cfg(all(rcc_f3, not(adc3_common)))] | ||
| 296 | adc34: None, | ||
| 297 | #[cfg(stm32f334)] | 322 | #[cfg(stm32f334)] |
| 298 | hrtim: hrtim, | 323 | hrtim: hrtim, |
| 299 | rtc: rtc, | 324 | rtc: rtc, |
| 325 | usb: usb, | ||
| 326 | lse: None, | ||
| 300 | ); | 327 | ); |
| 301 | } | 328 | } |
| 302 | 329 | ||
| 303 | #[inline] | 330 | mod max { |
| 304 | fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) { | 331 | use core::ops::RangeInclusive; |
| 305 | match (config.sysclk, config.hse) { | ||
| 306 | (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), | ||
| 307 | (Some(sysclk), None) if sysclk == HSI_FREQ => (HSI_FREQ, None), | ||
| 308 | // If the user selected System clock is different from HSI or HSE | ||
| 309 | // we will have to setup PLL clock source | ||
| 310 | (Some(sysclk), _) => { | ||
| 311 | let (sysclk, pll_config) = calc_pll(config, sysclk); | ||
| 312 | (sysclk, Some(pll_config)) | ||
| 313 | } | ||
| 314 | (None, Some(hse)) => (hse, None), | ||
| 315 | (None, None) => (HSI_FREQ, None), | ||
| 316 | } | ||
| 317 | } | ||
| 318 | 332 | ||
| 319 | #[inline] | 333 | use crate::time::Hertz; |
| 320 | fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { | ||
| 321 | // Calculates the Multiplier and the Divisor to arrive at | ||
| 322 | // the required System clock from PLL source frequency | ||
| 323 | let get_mul_div = |sysclk, pllsrcclk| { | ||
| 324 | let bus_div = gcd(sysclk, pllsrcclk); | ||
| 325 | let mut multiplier = sysclk / bus_div; | ||
| 326 | let mut divisor = pllsrcclk / bus_div; | ||
| 327 | // Minimum PLL multiplier is two | ||
| 328 | if multiplier == 1 { | ||
| 329 | multiplier *= 2; | ||
| 330 | divisor *= 2; | ||
| 331 | } | ||
| 332 | assert!(multiplier <= 16); | ||
| 333 | assert!(divisor <= 16); | ||
| 334 | (multiplier, divisor) | ||
| 335 | }; | ||
| 336 | // Based on the source of Pll, we calculate the actual system clock | ||
| 337 | // frequency, PLL's source identifier, multiplier and divisor | ||
| 338 | let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse { | ||
| 339 | Some(Hertz(hse)) => { | ||
| 340 | let (multiplier, divisor) = get_mul_div(sysclk, hse); | ||
| 341 | ( | ||
| 342 | Hertz((hse / divisor) * multiplier), | ||
| 343 | Pllsrc::HSE_DIV_PREDIV, | ||
| 344 | into_pll_mul(multiplier), | ||
| 345 | Some(into_pre_div(divisor)), | ||
| 346 | ) | ||
| 347 | } | ||
| 348 | None => { | ||
| 349 | cfg_if::cfg_if! { | ||
| 350 | // For some chips PREDIV is always two, and cannot be changed | ||
| 351 | if #[cfg(any(flashsize_d, flashsize_e))] { | ||
| 352 | let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0); | ||
| 353 | ( | ||
| 354 | Hertz((HSI_FREQ.0 / divisor) * multiplier), | ||
| 355 | Pllsrc::HSI_DIV_PREDIV, | ||
| 356 | into_pll_mul(multiplier), | ||
| 357 | Some(into_pre_div(divisor)), | ||
| 358 | ) | ||
| 359 | } else { | ||
| 360 | let pllsrcclk = HSI_FREQ.0 / 2; | ||
| 361 | let multiplier = sysclk / pllsrcclk; | ||
| 362 | assert!(multiplier <= 16); | ||
| 363 | ( | ||
| 364 | Hertz(pllsrcclk * multiplier), | ||
| 365 | Pllsrc::HSI_DIV2, | ||
| 366 | into_pll_mul(multiplier), | ||
| 367 | None, | ||
| 368 | ) | ||
| 369 | } | ||
| 370 | } | ||
| 371 | } | ||
| 372 | }; | ||
| 373 | ( | ||
| 374 | act_sysclk, | ||
| 375 | PllConfig { | ||
| 376 | pll_src, | ||
| 377 | pll_mul, | ||
| 378 | pll_div, | ||
| 379 | }, | ||
| 380 | ) | ||
| 381 | } | ||
| 382 | 334 | ||
| 383 | #[inline] | 335 | pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(32_000_000); |
| 384 | #[allow(unused_variables)] | 336 | pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(32_000_000); |
| 385 | fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option<PllConfig>) -> Usbpre { | ||
| 386 | cfg_if::cfg_if! { | ||
| 387 | // Some chips do not have USB | ||
| 388 | if #[cfg(any(stm32f301, stm32f318, stm32f334))] { | ||
| 389 | panic!("USB clock not supported by the chip"); | ||
| 390 | } else { | ||
| 391 | let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000)); | ||
| 392 | match (usb_ok, sysclk) { | ||
| 393 | (true, Hertz(72_000_000)) => Usbpre::DIV1_5, | ||
| 394 | (true, Hertz(48_000_000)) => Usbpre::DIV1, | ||
| 395 | _ => panic!( | ||
| 396 | "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" | ||
| 397 | ), | ||
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | // This function assumes cases when multiplier is one and it | ||
| 404 | // being greater than 16 is made impossible | ||
| 405 | #[inline] | ||
| 406 | fn into_pll_mul(multiplier: u32) -> Pllmul { | ||
| 407 | match multiplier { | ||
| 408 | 2 => Pllmul::MUL2, | ||
| 409 | 3 => Pllmul::MUL3, | ||
| 410 | 4 => Pllmul::MUL4, | ||
| 411 | 5 => Pllmul::MUL5, | ||
| 412 | 6 => Pllmul::MUL6, | ||
| 413 | 7 => Pllmul::MUL7, | ||
| 414 | 8 => Pllmul::MUL8, | ||
| 415 | 9 => Pllmul::MUL9, | ||
| 416 | 10 => Pllmul::MUL10, | ||
| 417 | 11 => Pllmul::MUL11, | ||
| 418 | 12 => Pllmul::MUL12, | ||
| 419 | 13 => Pllmul::MUL13, | ||
| 420 | 14 => Pllmul::MUL14, | ||
| 421 | 15 => Pllmul::MUL15, | ||
| 422 | 16 => Pllmul::MUL16, | ||
| 423 | _ => unreachable!(), | ||
| 424 | } | ||
| 425 | } | ||
| 426 | 337 | ||
| 427 | // This function assumes the incoming divisor cannot be greater | 338 | pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000); |
| 428 | // than 16 | 339 | pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(36_000_000); |
| 429 | #[inline] | 340 | pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000); |
| 430 | fn into_pre_div(divisor: u32) -> Prediv { | ||
| 431 | match divisor { | ||
| 432 | 1 => Prediv::DIV1, | ||
| 433 | 2 => Prediv::DIV2, | ||
| 434 | 3 => Prediv::DIV3, | ||
| 435 | 4 => Prediv::DIV4, | ||
| 436 | 5 => Prediv::DIV5, | ||
| 437 | 6 => Prediv::DIV6, | ||
| 438 | 7 => Prediv::DIV7, | ||
| 439 | 8 => Prediv::DIV8, | ||
| 440 | 9 => Prediv::DIV9, | ||
| 441 | 10 => Prediv::DIV10, | ||
| 442 | 11 => Prediv::DIV11, | ||
| 443 | 12 => Prediv::DIV12, | ||
| 444 | 13 => Prediv::DIV13, | ||
| 445 | 14 => Prediv::DIV14, | ||
| 446 | 15 => Prediv::DIV15, | ||
| 447 | 16 => Prediv::DIV16, | ||
| 448 | _ => unreachable!(), | ||
| 449 | } | ||
| 450 | } | ||
| 451 | 341 | ||
| 452 | // Determine GCD using Euclidean algorithm | 342 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(24_000_000); |
| 453 | #[inline] | 343 | pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(72_000_000); |
| 454 | fn gcd(mut a: u32, mut b: u32) -> u32 { | ||
| 455 | while b != 0 { | ||
| 456 | let r = a % b; | ||
| 457 | a = b; | ||
| 458 | b = r; | ||
| 459 | } | ||
| 460 | a | ||
| 461 | } | 344 | } |
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index eaaf8071c..db0df9fac 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs | |||
| @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; | |||
| 4 | 4 | ||
| 5 | use crate::gpio::sealed::AFType; | 5 | use crate::gpio::sealed::AFType; |
| 6 | use crate::gpio::Speed; | 6 | use crate::gpio::Speed; |
| 7 | #[cfg(not(stm32f1))] | 7 | #[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] |
| 8 | pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; | 8 | pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; |
| 9 | #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] | 9 | #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] |
| 10 | pub use crate::pac::rcc::vals::Mcosel as McoSource; | 10 | pub use crate::pac::rcc::vals::Mcosel as McoSource; |
| @@ -13,10 +13,16 @@ pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; | |||
| 13 | use crate::pac::RCC; | 13 | use crate::pac::RCC; |
| 14 | use crate::{peripherals, Peripheral}; | 14 | use crate::{peripherals, Peripheral}; |
| 15 | 15 | ||
| 16 | #[cfg(any(stm32f1, rcc_f3v1, rcc_f37))] | ||
| 17 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] | ||
| 18 | pub enum McoPrescaler { | ||
| 19 | DIV1, | ||
| 20 | } | ||
| 21 | |||
| 16 | pub(crate) mod sealed { | 22 | pub(crate) mod sealed { |
| 17 | pub trait McoInstance { | 23 | pub trait McoInstance { |
| 18 | type Source; | 24 | type Source; |
| 19 | unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); | 25 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); |
| 20 | } | 26 | } |
| 21 | } | 27 | } |
| 22 | 28 | ||
| @@ -29,7 +35,7 @@ macro_rules! impl_peri { | |||
| 29 | impl sealed::McoInstance for peripherals::$peri { | 35 | impl sealed::McoInstance for peripherals::$peri { |
| 30 | type Source = $source; | 36 | type Source = $source; |
| 31 | 37 | ||
| 32 | unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { | 38 | unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { |
| 33 | #[cfg(not(any(stm32u5, stm32wba)))] | 39 | #[cfg(not(any(stm32u5, stm32wba)))] |
| 34 | let r = RCC.cfgr(); | 40 | let r = RCC.cfgr(); |
| 35 | #[cfg(any(stm32u5, stm32wba))] | 41 | #[cfg(any(stm32u5, stm32wba))] |
| @@ -37,8 +43,8 @@ macro_rules! impl_peri { | |||
| 37 | 43 | ||
| 38 | r.modify(|w| { | 44 | r.modify(|w| { |
| 39 | w.$set_source(source); | 45 | w.$set_source(source); |
| 40 | #[cfg(not(stm32f1))] | 46 | #[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] |
| 41 | w.$set_prescaler(prescaler); | 47 | w.$set_prescaler(_prescaler); |
| 42 | }); | 48 | }); |
| 43 | } | 49 | } |
| 44 | } | 50 | } |
| @@ -68,16 +74,12 @@ impl<'d, T: McoInstance> Mco<'d, T> { | |||
| 68 | _peri: impl Peripheral<P = T> + 'd, | 74 | _peri: impl Peripheral<P = T> + 'd, |
| 69 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, | 75 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, |
| 70 | source: T::Source, | 76 | source: T::Source, |
| 71 | #[cfg(not(stm32f1))] prescaler: McoPrescaler, | 77 | prescaler: McoPrescaler, |
| 72 | ) -> Self { | 78 | ) -> Self { |
| 73 | into_ref!(pin); | 79 | into_ref!(pin); |
| 74 | 80 | ||
| 75 | critical_section::with(|_| unsafe { | 81 | critical_section::with(|_| unsafe { |
| 76 | T::apply_clock_settings( | 82 | T::apply_clock_settings(source, prescaler); |
| 77 | source, | ||
| 78 | #[cfg(not(stm32f1))] | ||
| 79 | prescaler, | ||
| 80 | ); | ||
| 81 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | 83 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); |
| 82 | pin.set_speed(Speed::VeryHigh); | 84 | pin.set_speed(Speed::VeryHigh); |
| 83 | }); | 85 | }); |
diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f3/src/bin/hello.rs +++ b/examples/stm32f3/src/bin/hello.rs | |||
| @@ -3,16 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | ||
| 7 | use embassy_stm32::Config; | 6 | use embassy_stm32::Config; |
| 8 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 9 | ||
| 11 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) -> ! { | 11 | async fn main(_spawner: Spawner) -> ! { |
| 13 | let mut config = Config::default(); | 12 | let config = Config::default(); |
| 14 | config.rcc.hse = Some(Hertz(8_000_000)); | ||
| 15 | config.rcc.sysclk = Some(Hertz(16_000_000)); | ||
| 16 | let _p = embassy_stm32::init(config); | 13 | let _p = embassy_stm32::init(config); |
| 17 | 14 | ||
| 18 | loop { | 15 | loop { |
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index cf9ecedfa..ee1c43afd 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs | |||
| @@ -21,11 +21,22 @@ bind_interrupts!(struct Irqs { | |||
| 21 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| 22 | async fn main(_spawner: Spawner) { | 22 | async fn main(_spawner: Spawner) { |
| 23 | let mut config = Config::default(); | 23 | let mut config = Config::default(); |
| 24 | config.rcc.hse = Some(mhz(8)); | 24 | { |
| 25 | config.rcc.sysclk = Some(mhz(48)); | 25 | use embassy_stm32::rcc::*; |
| 26 | config.rcc.pclk1 = Some(mhz(24)); | 26 | config.rcc.hse = Some(Hse { |
| 27 | config.rcc.pclk2 = Some(mhz(24)); | 27 | freq: mhz(8), |
| 28 | config.rcc.pll48 = true; | 28 | mode: HseMode::Bypass, |
| 29 | }); | ||
| 30 | config.rcc.pll = Some(Pll { | ||
| 31 | src: PllSource::HSE, | ||
| 32 | prediv: PllPreDiv::DIV1, | ||
| 33 | mul: PllMul::MUL9, | ||
| 34 | }); | ||
| 35 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 36 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 37 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 38 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 39 | } | ||
| 29 | let p = embassy_stm32::init(config); | 40 | let p = embassy_stm32::init(config); |
| 30 | 41 | ||
| 31 | info!("Hello World!"); | 42 | info!("Hello World!"); |
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 063ee9dac..a9fb7f1a6 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs | |||
| @@ -5,7 +5,6 @@ use defmt::info; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::peripherals::ADC1; | 7 | use embassy_stm32::peripherals::ADC1; |
| 8 | use embassy_stm32::rcc::{AdcClockSource, Adcpres}; | ||
| 9 | use embassy_stm32::time::mhz; | 8 | use embassy_stm32::time::mhz; |
| 10 | use embassy_stm32::{adc, bind_interrupts, Config}; | 9 | use embassy_stm32::{adc, bind_interrupts, Config}; |
| 11 | use embassy_time::{Delay, Timer}; | 10 | use embassy_time::{Delay, Timer}; |
| @@ -18,12 +17,23 @@ bind_interrupts!(struct Irqs { | |||
| 18 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 19 | async fn main(_spawner: Spawner) -> ! { | 18 | async fn main(_spawner: Spawner) -> ! { |
| 20 | let mut config = Config::default(); | 19 | let mut config = Config::default(); |
| 21 | config.rcc.sysclk = Some(mhz(64)); | 20 | { |
| 22 | config.rcc.hclk = Some(mhz(64)); | 21 | use embassy_stm32::rcc::*; |
| 23 | config.rcc.pclk1 = Some(mhz(32)); | 22 | config.rcc.hse = Some(Hse { |
| 24 | config.rcc.pclk2 = Some(mhz(64)); | 23 | freq: mhz(8), |
| 25 | config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); | 24 | mode: HseMode::Bypass, |
| 26 | 25 | }); | |
| 26 | config.rcc.pll = Some(Pll { | ||
| 27 | src: PllSource::HSE, | ||
| 28 | prediv: PllPreDiv::DIV1, | ||
| 29 | mul: PllMul::MUL9, | ||
| 30 | }); | ||
| 31 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 32 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 33 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 34 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 35 | config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); | ||
| 36 | } | ||
| 27 | let mut p = embassy_stm32::init(config); | 37 | let mut p = embassy_stm32::init(config); |
| 28 | 38 | ||
| 29 | info!("create adc..."); | 39 | info!("create adc..."); |
diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f334/src/bin/hello.rs +++ b/examples/stm32f334/src/bin/hello.rs | |||
| @@ -3,16 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | ||
| 7 | use embassy_stm32::Config; | 6 | use embassy_stm32::Config; |
| 8 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 9 | ||
| 11 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) -> ! { | 11 | async fn main(_spawner: Spawner) -> ! { |
| 13 | let mut config = Config::default(); | 12 | let config = Config::default(); |
| 14 | config.rcc.hse = Some(Hertz(8_000_000)); | ||
| 15 | config.rcc.sysclk = Some(Hertz(16_000_000)); | ||
| 16 | let _p = embassy_stm32::init(config); | 13 | let _p = embassy_stm32::init(config); |
| 17 | 14 | ||
| 18 | loop { | 15 | loop { |
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 850a0e335..6f25191be 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs | |||
| @@ -6,7 +6,6 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::opamp::{OpAmp, OpAmpGain}; | 7 | use embassy_stm32::opamp::{OpAmp, OpAmpGain}; |
| 8 | use embassy_stm32::peripherals::ADC2; | 8 | use embassy_stm32::peripherals::ADC2; |
| 9 | use embassy_stm32::rcc::{AdcClockSource, Adcpres}; | ||
| 10 | use embassy_stm32::time::mhz; | 9 | use embassy_stm32::time::mhz; |
| 11 | use embassy_stm32::{adc, bind_interrupts, Config}; | 10 | use embassy_stm32::{adc, bind_interrupts, Config}; |
| 12 | use embassy_time::{Delay, Timer}; | 11 | use embassy_time::{Delay, Timer}; |
| @@ -19,12 +18,23 @@ bind_interrupts!(struct Irqs { | |||
| 19 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) -> ! { | 19 | async fn main(_spawner: Spawner) -> ! { |
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.rcc.sysclk = Some(mhz(64)); | 21 | { |
| 23 | config.rcc.hclk = Some(mhz(64)); | 22 | use embassy_stm32::rcc::*; |
| 24 | config.rcc.pclk1 = Some(mhz(32)); | 23 | config.rcc.hse = Some(Hse { |
| 25 | config.rcc.pclk2 = Some(mhz(64)); | 24 | freq: mhz(8), |
| 26 | config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); | 25 | mode: HseMode::Bypass, |
| 27 | 26 | }); | |
| 27 | config.rcc.pll = Some(Pll { | ||
| 28 | src: PllSource::HSE, | ||
| 29 | prediv: PllPreDiv::DIV1, | ||
| 30 | mul: PllMul::MUL9, | ||
| 31 | }); | ||
| 32 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 33 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 34 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 35 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 36 | config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); | ||
| 37 | } | ||
| 28 | let mut p = embassy_stm32::init(config); | 38 | let mut p = embassy_stm32::init(config); |
| 29 | 39 | ||
| 30 | info!("create adc..."); | 40 | info!("create adc..."); |
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index c149cad92..7fc1ea926 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::hrtim::*; | 6 | use embassy_stm32::hrtim::*; |
| 7 | use embassy_stm32::rcc::HrtimClockSource; | ||
| 8 | use embassy_stm32::time::{khz, mhz}; | 7 | use embassy_stm32::time::{khz, mhz}; |
| 9 | use embassy_stm32::Config; | 8 | use embassy_stm32::Config; |
| 10 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| @@ -12,14 +11,26 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 12 | 11 | ||
| 13 | #[embassy_executor::main] | 12 | #[embassy_executor::main] |
| 14 | async fn main(_spawner: Spawner) { | 13 | async fn main(_spawner: Spawner) { |
| 15 | let mut config: Config = Default::default(); | 14 | let mut config = Config::default(); |
| 16 | config.rcc.sysclk = Some(mhz(64)); | 15 | { |
| 17 | config.rcc.hclk = Some(mhz(64)); | 16 | use embassy_stm32::rcc::*; |
| 18 | config.rcc.pclk1 = Some(mhz(32)); | 17 | config.rcc.hse = Some(Hse { |
| 19 | config.rcc.pclk2 = Some(mhz(64)); | 18 | freq: mhz(8), |
| 20 | config.rcc.hrtim = HrtimClockSource::PllClk; | 19 | mode: HseMode::Bypass, |
| 21 | 20 | }); | |
| 21 | config.rcc.pll = Some(Pll { | ||
| 22 | src: PllSource::HSE, | ||
| 23 | prediv: PllPreDiv::DIV1, | ||
| 24 | mul: PllMul::MUL9, | ||
| 25 | }); | ||
| 26 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 27 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 28 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 29 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 30 | config.rcc.hrtim = HrtimClockSource::PllClk; | ||
| 31 | } | ||
| 22 | let p = embassy_stm32::init(config); | 32 | let p = embassy_stm32::init(config); |
| 33 | |||
| 23 | info!("Hello World!"); | 34 | info!("Hello World!"); |
| 24 | 35 | ||
| 25 | let ch1 = PwmPin::new_cha(p.PA8); | 36 | let ch1 = PwmPin::new_cha(p.PA8); |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index fefe72c86..36fe8a235 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -276,6 +276,24 @@ pub fn config() -> Config { | |||
| 276 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 276 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | #[cfg(feature = "stm32f303ze")] | ||
| 280 | { | ||
| 281 | use embassy_stm32::rcc::*; | ||
| 282 | config.rcc.hse = Some(Hse { | ||
| 283 | freq: Hertz(8_000_000), | ||
| 284 | mode: HseMode::Bypass, | ||
| 285 | }); | ||
| 286 | config.rcc.pll = Some(Pll { | ||
| 287 | src: PllSource::HSE, | ||
| 288 | prediv: PllPreDiv::DIV1, | ||
| 289 | mul: PllMul::MUL9, | ||
| 290 | }); | ||
| 291 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 292 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 293 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 294 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 295 | } | ||
| 296 | |||
| 279 | #[cfg(feature = "stm32f429zi")] | 297 | #[cfg(feature = "stm32f429zi")] |
| 280 | { | 298 | { |
| 281 | use embassy_stm32::rcc::*; | 299 | use embassy_stm32::rcc::*; |
