py32_hal/rcc/
f0.rs

1// The following code is modified from embassy-stm32
2// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
3// Special thanks to the Embassy Project and its contributors for their work!
4
5// use crate::pac::flash::vals::Latency;
6use crate::pac::rcc::vals::Pllsrc;
7// pub use crate::pac::rcc::vals::Prediv as PllPreDiv;
8#[cfg(rcc_f030)]
9use crate::pac::rcc::vals::HseFreq;
10#[cfg(rcc_f072)]
11pub use crate::pac::rcc::vals::Pllmul as PllMul;
12pub use crate::pac::rcc::vals::{
13    Hpre as AHBPrescaler, HsiFs, Hsidiv, Ppre as APBPrescaler, Sw as Sysclk,
14};
15
16use crate::pac::{CONFIGBYTES, FLASH, RCC};
17use crate::time::Hertz;
18
19// /// HSI speed
20// pub const HSI_FREQ: Hertz = Hertz(8_000_000);
21
22#[derive(Clone, Copy, Eq, PartialEq)]
23pub enum HseMode {
24    /// crystal/ceramic oscillator (HSEBYP=0)
25    Oscillator,
26    /// external analog clock (low swing) (HSEBYP=1)
27    Bypass,
28}
29
30#[derive(Clone, Copy, Eq, PartialEq)]
31pub struct Hse {
32    /// HSE frequency.
33    pub freq: Hertz,
34    /// HSE mode.
35    pub mode: HseMode,
36}
37
38#[derive(Clone, Copy, Eq, PartialEq)]
39pub struct Hsi {
40    /// HSE frequency.
41    pub freq: Hertz,
42    /// HSE mode.
43    pub mode: HseMode,
44}
45
46#[derive(Clone, Copy, Eq, PartialEq)]
47pub enum PllSource {
48    HSE,
49    HSI,
50}
51
52#[derive(Clone, Copy)]
53pub struct Pll {
54    pub src: PllSource,
55
56    // /// PLL pre-divider.
57    // ///
58    // /// On some chips, this must be 2 if `src == HSI`. Init will panic if this is not the case.
59    // pub prediv: PllPreDiv,
60    #[cfg(rcc_f072)]
61    /// PLL multiplication factor.
62    pub mul: PllMul,
63}
64
65/// Clocks configutation
66#[non_exhaustive]
67#[derive(Clone, Copy)]
68pub struct Config {
69    pub hsi: Option<HsiFs>,
70    pub hsidiv: Hsidiv,
71    pub hse: Option<Hse>,
72    pub sys: Sysclk,
73
74    pub pll: Option<Pll>,
75
76    pub ahb_pre: AHBPrescaler,
77    pub apb1_pre: APBPrescaler,
78    /// Per-peripheral kernel clock selection muxes
79    pub mux: super::mux::ClockMux,
80    // pub ls: super::LsConfig,
81}
82
83impl Default for Config {
84    fn default() -> Self {
85        Self {
86            hsi: Some(HsiFs::HSI_8MHZ),
87            hse: None,
88            sys: Sysclk::HSI,
89            hsidiv: Hsidiv::DIV1,
90            pll: None,
91            ahb_pre: AHBPrescaler::DIV1,
92            apb1_pre: APBPrescaler::DIV1,
93            // ls: Default::default(),
94            mux: Default::default(),
95        }
96    }
97}
98
99/// Initialize and Set the clock frequencies
100pub(crate) unsafe fn init(config: Config) {
101    // Turn on the HSI
102    RCC.cr().modify(|w| w.set_hsion(true));
103    let hsi_value = if let Some(value) = config.hsi {
104        let hsi_trimming_bytes = CONFIGBYTES.hsi_trimming(value as usize).read();
105
106        assert_eq!(hsi_trimming_bytes.hsi_fs(), value as u8);
107
108        RCC.icscr().modify(|w| {
109            w.set_hsi_fs(value);
110            w.set_hsi_trim(hsi_trimming_bytes.hsi_trim());
111        });
112
113        match value {
114            HsiFs::HSI_4MHZ => Some(Hertz(4_000_000)),
115            HsiFs::HSI_8MHZ => Some(Hertz(8_000_000)),
116            HsiFs::HSI_16MHZ => Some(Hertz(16_000_000)),
117            HsiFs::HSI_22_12MHZ => Some(Hertz(22_120_000)),
118            HsiFs::HSI_24MHZ => Some(Hertz(24_000_000)),
119            _ => unreachable!(),
120        }
121    } else {
122        None
123    };
124    while !RCC.cr().read().hsirdy() {}
125
126    // Use the HSI clock as system clock during the actual clock setup
127    RCC.cfgr().modify(|w| w.set_sw(Sysclk::HSI));
128    while RCC.cfgr().read().sws() != Sysclk::HSI {}
129
130    RCC.cr().modify(|w| w.set_hsidiv(config.hsidiv));
131
132    // Configure HSI
133    let hsi = config.hsi;
134
135    // Configure HSE
136    let hse = match config.hse {
137        None => {
138            RCC.cr().modify(|w| w.set_hseon(false));
139            None
140        }
141        Some(hse) => {
142            match hse.mode {
143                HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
144                HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
145            }
146
147            #[cfg(rcc_f030)]
148            RCC.ecscr().modify(|w| {
149                w.set_hse_freq(match hse.freq.0 {
150                    ..=8_000_000 => HseFreq::RANGE1,
151                    ..=16_000_000 => HseFreq::RANGE2,
152                    _ => HseFreq::RANGE3,
153                })
154            });
155            RCC.cr()
156                .modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
157            RCC.cr().modify(|w| w.set_hseon(true));
158            while !RCC.cr().read().hserdy() {}
159            Some(hse.freq)
160        }
161    };
162    // Configure PLL
163    let pll = match config.pll {
164        None => None,
165        Some(pll) => {
166            let (src_val, src_freq) = match pll.src {
167                PllSource::HSE => (Pllsrc::HSE, unwrap!(hse)),
168                PllSource::HSI => (Pllsrc::HSI, unwrap!(hsi_value)),
169            };
170            #[cfg(rcc_f030)]
171            let out_freq = src_freq * 2u8;
172            #[cfg(rcc_f072)]
173            let out_freq = src_freq * pll.mul;
174            assert!(max::PLL_IN.contains(&src_freq));
175            // assert!(max::PLL_OUT.contains(&pll.src.out_freq(pll.mul)));
176
177            RCC.cr().modify(|w| w.set_pllon(false));
178            while RCC.cr().read().pllrdy() {}
179
180            RCC.pllcfgr().modify(|w| {
181                #[cfg(rcc_f072)]
182                w.set_pllmul(pll.mul);
183                w.set_pllsrc(src_val);
184            });
185            RCC.cr().modify(|w| w.set_pllon(true));
186            cortex_m::asm::delay(1_000);
187            while !RCC.cr().read().pllrdy() {}
188            Some(out_freq)
189        }
190    };
191
192    // let usb = match pll {
193    //     Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5),
194    //     Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1),
195    //     _ => None,
196    // }
197    // .map(|usbpre| {
198    //     RCC.cfgr().modify(|w| w.set_usbpre(usbpre));
199    //     Hertz(48_000_000)
200    // });
201
202    // Configure sysclk
203    let sys = match config.sys {
204        Sysclk::HSI => unwrap!(hsi_value) / config.hsidiv,
205        Sysclk::HSE => unwrap!(hse),
206        Sysclk::PLL => unwrap!(pll),
207        _ => unreachable!(),
208    };
209
210    let hclk1 = sys / config.ahb_pre;
211    let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
212
213    // assert!(max::HCLK.contains(&hclk));
214    // assert!(max::PCLK.contains(&pclk));
215
216    let latency: u8 = match hclk1.0 {
217        ..=24_000_000 => 0,
218        ..=48_000_000 => 1,
219        _ => 2,
220    };
221    FLASH.acr().modify(|w| {
222        #[cfg(rcc_f072)]
223        w.set_latency(latency);
224        #[cfg(rcc_f030)]
225        w.set_latency(latency != 0);
226    });
227    // Set prescalers
228    // CFGR has been written before (PLL, PLL48) don't overwrite these settings
229    RCC.cfgr().modify(|w| {
230        w.set_ppre(config.apb1_pre);
231        w.set_hpre(config.ahb_pre);
232    });
233
234    // Wait for the new prescalers to kick in
235    // "The clocks are divided with the new prescaler factor from
236    //  1 to 16 AHB cycles after write"
237    cortex_m::asm::delay(16);
238
239    // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings
240    RCC.cfgr().modify(|w| w.set_sw(config.sys));
241    while RCC.cfgr().read().sws() != config.sys {}
242
243    // Disable HSI if not used
244    if hsi == None {
245        RCC.cr().modify(|w| w.set_hsion(false));
246    }
247
248    // let rtc = config.ls.init();
249
250    /*
251    TODO: Maybe add something like this to clock_mux? How can we autogenerate the data for this?
252    let hrtim = match config.hrtim {
253        // Must be configured after the bus is ready, otherwise it won't work
254        HrtimClockSource::BusClk => None,
255        HrtimClockSource::PllClk => {
256            use crate::pac::rcc::vals::Timsw;
257
258            // Make sure that we're using the PLL
259            let pll = unwrap!(pll);
260            assert!((pclk2 == pll) || (pclk2 * 2u32 == pll));
261
262            RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P));
263
264            Some(pll * 2u32)
265        }
266    };
267     */
268
269    config.mux.init();
270
271    // set_clocks!(
272    //     hsi: hsi,
273    //     hse: hse,
274    //     pll: pll,
275    //     sys: Some(sys),
276    //     pclk1: Some(pclk1),
277    //     pclk1_tim: Some(pclk1_tim),
278    //     hclk1: Some(hclk1),
279    //     rtc: rtc,
280    //     // usb: usb,
281    //     lse: None,
282    // );
283
284    let clocks = crate::rcc::Clocks {
285        hclk1: Some(hclk1).into(),
286        pclk1: Some(pclk1).into(),
287        pclk1_tim: Some(pclk1_tim).into(),
288        sys: Some(sys).into(),
289        hsi: hsi_value.into(),
290        lse: None.into(),
291        pll: pll.into(),
292    };
293    crate::rcc::set_freqs(clocks);
294}
295
296mod max {
297    use core::ops::RangeInclusive;
298
299    use crate::time::Hertz;
300
301    pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(32_000_000);
302    pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(32_000_000);
303
304    // pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
305    // pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
306
307    #[cfg(any(rcc_f030, rcc_f072))]
308    pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(24_000_000);
309    // pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(48_000_000);
310}