diff options
| -rw-r--r-- | embassy-stm32/src/rcc/wba.rs | 193 |
1 files changed, 103 insertions, 90 deletions
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 1d04d480a..dfa236484 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Pllsrc, Sw}; | 1 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 2 | 2 | use crate::pac::rcc::regs::Cfgr1; | |
| 3 | pub use crate::pac::rcc::vals::{ | ||
| 4 | Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc, | ||
| 5 | }; | ||
| 3 | use crate::pac::{FLASH, RCC}; | 6 | use crate::pac::{FLASH, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 7 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| @@ -9,82 +12,108 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); | |||
| 9 | // HSE speed | 12 | // HSE speed |
| 10 | pub const HSE_FREQ: Hertz = Hertz(32_000_000); | 13 | pub const HSE_FREQ: Hertz = Hertz(32_000_000); |
| 11 | 14 | ||
| 12 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 15 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 13 | pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; | 16 | pub struct Hse { |
| 14 | 17 | pub prescaler: HsePrescaler, | |
| 15 | #[derive(Copy, Clone)] | ||
| 16 | pub enum ClockSrc { | ||
| 17 | HSE, | ||
| 18 | HSI, | ||
| 19 | } | ||
| 20 | |||
| 21 | #[derive(Clone, Copy, Debug)] | ||
| 22 | pub enum PllSource { | ||
| 23 | HSE, | ||
| 24 | HSI, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl Into<Pllsrc> for PllSource { | ||
| 28 | fn into(self) -> Pllsrc { | ||
| 29 | match self { | ||
| 30 | PllSource::HSE => Pllsrc::HSE, | ||
| 31 | PllSource::HSI => Pllsrc::HSI, | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | impl Into<Sw> for ClockSrc { | ||
| 37 | fn into(self) -> Sw { | ||
| 38 | match self { | ||
| 39 | ClockSrc::HSE => Sw::HSE, | ||
| 40 | ClockSrc::HSI => Sw::HSI, | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | 18 | } |
| 44 | 19 | ||
| 20 | /// Clocks configuration | ||
| 45 | pub struct Config { | 21 | pub struct Config { |
| 22 | // base clock sources | ||
| 23 | pub hsi: bool, | ||
| 24 | pub hse: Option<Hse>, | ||
| 25 | |||
| 26 | // sysclk, buses. | ||
| 46 | pub mux: ClockSrc, | 27 | pub mux: ClockSrc, |
| 47 | pub ahb_pre: AHBPrescaler, | 28 | pub ahb_pre: AHBPrescaler, |
| 48 | pub apb1_pre: APBPrescaler, | 29 | pub apb1_pre: APBPrescaler, |
| 49 | pub apb2_pre: APBPrescaler, | 30 | pub apb2_pre: APBPrescaler, |
| 50 | pub apb7_pre: APBPrescaler, | 31 | pub apb7_pre: APBPrescaler, |
| 32 | |||
| 33 | // low speed LSI/LSE/RTC | ||
| 51 | pub ls: super::LsConfig, | 34 | pub ls: super::LsConfig, |
| 35 | |||
| 36 | pub adc_clock_source: AdcClockSource, | ||
| 37 | |||
| 38 | pub voltage_scale: VoltageScale, | ||
| 52 | } | 39 | } |
| 53 | 40 | ||
| 54 | impl Default for Config { | 41 | impl Default for Config { |
| 55 | fn default() -> Self { | 42 | #[inline] |
| 56 | Self { | 43 | fn default() -> Config { |
| 44 | Config { | ||
| 45 | hse: None, | ||
| 46 | hsi: true, | ||
| 57 | mux: ClockSrc::HSI, | 47 | mux: ClockSrc::HSI, |
| 58 | ahb_pre: AHBPrescaler::DIV1, | 48 | ahb_pre: AHBPrescaler::DIV1, |
| 59 | apb1_pre: APBPrescaler::DIV1, | 49 | apb1_pre: APBPrescaler::DIV1, |
| 60 | apb2_pre: APBPrescaler::DIV1, | 50 | apb2_pre: APBPrescaler::DIV1, |
| 61 | apb7_pre: APBPrescaler::DIV1, | 51 | apb7_pre: APBPrescaler::DIV1, |
| 62 | ls: Default::default(), | 52 | ls: Default::default(), |
| 53 | adc_clock_source: AdcClockSource::HCLK1, | ||
| 54 | voltage_scale: VoltageScale::RANGE2, | ||
| 63 | } | 55 | } |
| 64 | } | 56 | } |
| 65 | } | 57 | } |
| 66 | 58 | ||
| 59 | fn hsi_enable() { | ||
| 60 | RCC.cr().modify(|w| w.set_hsion(true)); | ||
| 61 | while !RCC.cr().read().hsirdy() {} | ||
| 62 | } | ||
| 63 | |||
| 67 | pub(crate) unsafe fn init(config: Config) { | 64 | pub(crate) unsafe fn init(config: Config) { |
| 68 | let sys_clk = match config.mux { | 65 | // Switch to HSI to prevent problems with PLL configuration. |
| 69 | ClockSrc::HSE => { | 66 | if !RCC.cr().read().hsion() { |
| 70 | RCC.cr().write(|w| w.set_hseon(true)); | 67 | hsi_enable() |
| 71 | while !RCC.cr().read().hserdy() {} | 68 | } |
| 69 | if RCC.cfgr1().read().sws() != ClockSrc::HSI { | ||
| 70 | // Set HSI as a clock source, reset prescalers. | ||
| 71 | RCC.cfgr1().write_value(Cfgr1::default()); | ||
| 72 | // Wait for clock switch status bits to change. | ||
| 73 | while RCC.cfgr1().read().sws() != ClockSrc::HSI {} | ||
| 74 | } | ||
| 72 | 75 | ||
| 73 | HSE_FREQ | 76 | // Set voltage scale |
| 74 | } | 77 | crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale)); |
| 75 | ClockSrc::HSI => { | 78 | while !crate::pac::PWR.vosr().read().vosrdy() {} |
| 76 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 77 | while !RCC.cr().read().hsirdy() {} | ||
| 78 | 79 | ||
| 79 | HSI_FREQ | 80 | let rtc = config.ls.init(); |
| 80 | } | 81 | |
| 82 | let hsi = config.hsi.then(|| { | ||
| 83 | hsi_enable(); | ||
| 84 | |||
| 85 | HSI_FREQ | ||
| 86 | }); | ||
| 87 | |||
| 88 | let hse = config.hse.map(|hse| { | ||
| 89 | RCC.cr().write(|w| { | ||
| 90 | w.set_hseon(true); | ||
| 91 | w.set_hsepre(hse.prescaler); | ||
| 92 | }); | ||
| 93 | while !RCC.cr().read().hserdy() {} | ||
| 94 | |||
| 95 | HSE_FREQ | ||
| 96 | }); | ||
| 97 | |||
| 98 | let sys_clk = match config.mux { | ||
| 99 | ClockSrc::HSE => hse.unwrap(), | ||
| 100 | ClockSrc::HSI => hsi.unwrap(), | ||
| 101 | ClockSrc::_RESERVED_1 => unreachable!(), | ||
| 102 | ClockSrc::PLL1_R => todo!(), | ||
| 81 | }; | 103 | }; |
| 82 | 104 | ||
| 83 | // TODO make configurable | 105 | assert!(sys_clk.0 <= 100_000_000); |
| 84 | let power_vos = VoltageScale::RANGE1; | 106 | |
| 107 | let hclk1 = sys_clk / config.ahb_pre; | ||
| 108 | let hclk2 = hclk1; | ||
| 109 | let hclk4 = hclk1; | ||
| 110 | // TODO: hclk5 | ||
| 111 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); | ||
| 112 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); | ||
| 113 | let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre); | ||
| 85 | 114 | ||
| 86 | // states and programming delay | 115 | // Set flash wait states |
| 87 | let wait_states = match power_vos { | 116 | let flash_latency = match config.voltage_scale { |
| 88 | VoltageScale::RANGE1 => match sys_clk.0 { | 117 | VoltageScale::RANGE1 => match sys_clk.0 { |
| 89 | ..=32_000_000 => 0, | 118 | ..=32_000_000 => 0, |
| 90 | ..=64_000_000 => 1, | 119 | ..=64_000_000 => 1, |
| @@ -99,13 +128,24 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 99 | }, | 128 | }, |
| 100 | }; | 129 | }; |
| 101 | 130 | ||
| 102 | FLASH.acr().modify(|w| { | 131 | FLASH.acr().modify(|w| w.set_latency(flash_latency)); |
| 103 | w.set_latency(wait_states); | 132 | while FLASH.acr().read().latency() != flash_latency {} |
| 104 | }); | 133 | |
| 134 | // Set sram wait states | ||
| 135 | let _sram_latency = match config.voltage_scale { | ||
| 136 | VoltageScale::RANGE1 => 0, | ||
| 137 | VoltageScale::RANGE2 => match sys_clk.0 { | ||
| 138 | ..=12_000_000 => 0, | ||
| 139 | ..=16_000_000 => 1, | ||
| 140 | _ => 2, | ||
| 141 | }, | ||
| 142 | }; | ||
| 143 | // TODO: Set the SRAM wait states | ||
| 105 | 144 | ||
| 106 | RCC.cfgr1().modify(|w| { | 145 | RCC.cfgr1().modify(|w| { |
| 107 | w.set_sw(config.mux.into()); | 146 | w.set_sw(config.mux); |
| 108 | }); | 147 | }); |
| 148 | while RCC.cfgr1().read().sws() != config.mux {} | ||
| 109 | 149 | ||
| 110 | RCC.cfgr2().modify(|w| { | 150 | RCC.cfgr2().modify(|w| { |
| 111 | w.set_hpre(config.ahb_pre); | 151 | w.set_hpre(config.ahb_pre); |
| @@ -113,45 +153,18 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 113 | w.set_ppre2(config.apb2_pre); | 153 | w.set_ppre2(config.apb2_pre); |
| 114 | }); | 154 | }); |
| 115 | 155 | ||
| 116 | RCC.cfgr3().modify(|w| { | 156 | RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); |
| 117 | w.set_ppre7(config.apb7_pre); | ||
| 118 | }); | ||
| 119 | |||
| 120 | let ahb_freq = sys_clk / config.ahb_pre; | ||
| 121 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 122 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 123 | pre => { | ||
| 124 | let freq = ahb_freq / pre; | ||
| 125 | (freq, freq * 2u32) | ||
| 126 | } | ||
| 127 | }; | ||
| 128 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 129 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 130 | pre => { | ||
| 131 | let freq = ahb_freq / pre; | ||
| 132 | (freq, freq * 2u32) | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { | ||
| 136 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 137 | pre => { | ||
| 138 | let freq = ahb_freq / pre; | ||
| 139 | (freq, freq * 2u32) | ||
| 140 | } | ||
| 141 | }; | ||
| 142 | |||
| 143 | let rtc = config.ls.init(); | ||
| 144 | 157 | ||
| 145 | set_freqs(Clocks { | 158 | set_freqs(Clocks { |
| 146 | sys: sys_clk, | 159 | sys: sys_clk, |
| 147 | hclk1: ahb_freq, | 160 | hclk1, |
| 148 | hclk2: ahb_freq, | 161 | hclk2, |
| 149 | hclk4: ahb_freq, | 162 | hclk4, |
| 150 | pclk1: apb1_freq, | 163 | pclk1, |
| 151 | pclk2: apb2_freq, | 164 | pclk2, |
| 152 | pclk7: apb7_freq, | 165 | pclk7, |
| 153 | pclk1_tim: apb1_tim_freq, | 166 | pclk1_tim, |
| 154 | pclk2_tim: apb2_tim_freq, | 167 | pclk2_tim, |
| 155 | rtc, | 168 | rtc, |
| 156 | }); | 169 | }); |
| 157 | } | 170 | } |
