stm32f4xx/clocks/
pll.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive SRL.
4//
5// Author: Ioan-Cristian CÎRSTEA <ioan.cirstea@oxidos.io>
6
7//! Main phase-locked loop (PLL) clock driver for the STM32F4xx family. [^doc_ref]
8//!
9//! Many boards of the STM32F4xx family provide several PLL clocks. However, all of them have a
10//! main PLL clock. This driver is designed for the main PLL clock. It will be simply referred as
11//! the PLL clock.
12//!
13//! The PLL clock is composed of two outputs:
14//!
15//! + the main one used for the system clock
16//! + the PLL48CLK used for USB OTG FS, the random number generator and SDIO clocks
17//!
18//! # Implemented features
19//!
20//! - [x] Default configuration of 96MHz with reduced PLL jitter
21//! - [x] 1MHz frequency precision
22//! - [x] Support for 13-216MHz frequency range
23//! - [x] Support for PLL48CLK output
24//!
25//! # Missing features
26//!
27//! - [ ] Precision higher than 1MHz
28//! - [ ] Source selection
29//! - [ ] Precise control over the PLL48CLK frequency
30//!
31//! # Usage
32//!
33//! For the purposes of brevity, any error checking has been removed. In real applications, always
34//! check the return values of the [Pll] methods.
35//!
36//! First, get a reference to the [Pll] struct:
37//! ```rust,ignore
38//! let pll = &peripherals.stm32f4.clocks.pll;
39//! ```
40//!
41//! ## Start the clock with a given frequency
42//!
43//! ```rust,ignore
44//! pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 100); // 100MHz
45//! pll.enable();
46//! ```
47//!
48//! ## Stop the clock
49//!
50//! ```rust,ignore
51//! pll.disable();
52//! ```
53//!
54//! ## Check whether the PLL clock is running or not
55//! ```rust,ignore
56//! if pll.is_enabled() {
57//!     // do something...
58//! } else {
59//!     // do something...
60//! }
61//! ```
62//!
63//! ## Check the clock frequency
64//!
65//! ```rust,ignore
66//! let optional_pll_frequency = pll.get_frequency_mhz();
67//! if let None = optional_pll_frequency {
68//!     /* Clock stopped */
69//! }
70//! let pll_frequency = optional_pll_frequency.unwrap();
71//! /* Computations based on the PLL frequency */
72//! ```
73//!
74//! ## Reconfigure the clock once started
75//!
76//! ```rust,ignore
77//! pll.disable(); // The PLL clock can't be configured while running
78//! pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 50); // 50MHz
79//! pll.enable();
80//! ```
81//!
82//! ## Configure the PLL clock so that PLL48CLK output is correctly calibrated
83//! ```rust,ignore
84//! // The frequency of the PLL clock must be 1, 1.5, 2, 2.5, 3, 3.5 or 4 x 48MHz in order to get
85//! // 48MHz output. Otherwise, the driver will attempt to get the closest frequency lower than 48MHz
86//! pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 72); // 72MHz = 48MHz * 1.5
87//! pll.enable();
88//! ```
89//!
90//! ## Check if the PLL48CLK output is calibrated.
91//! ```rust,ignore
92//! if !pll.is_pll48_calibrated() {
93//!     /* Handle the case when it is not calibrated */
94//! }
95//! ```
96//!
97//! ## Get the frequency of the PLL48CLK output
98//!
99//! ```rust,ignore
100//! let optional_pll48_frequency = pll.get_frequency_mhz();
101//! if let None = optional_pll48_frequency {
102//!     /* Clock stopped */
103//! }
104//! let pll48_frequency = optional_pll48_frequency.unwrap();
105//! ```
106//!
107//! [^doc_ref]: See 6.2.3 in the documentation.
108
109use crate::chip_specific::clock_constants;
110use crate::clocks::hsi::HSI_FREQUENCY_MHZ;
111use crate::rcc::Rcc;
112use crate::rcc::SysClockSource;
113use crate::rcc::{PllSource, PLLM, PLLP, PLLQ};
114use crate::rcc::{DEFAULT_PLLM_VALUE, DEFAULT_PLLN_VALUE, DEFAULT_PLLP_VALUE, DEFAULT_PLLQ_VALUE};
115
116use kernel::debug;
117use kernel::utilities::cells::OptionalCell;
118use kernel::ErrorCode;
119
120use core::cell::Cell;
121use core::marker::PhantomData;
122
123/// Main PLL clock structure.
124pub struct Pll<'a, PllConstants> {
125    rcc: &'a Rcc,
126    frequency_mhz: OptionalCell<usize>,
127    pll48_frequency_mhz: OptionalCell<usize>,
128    pll48_calibrated: Cell<bool>,
129    _marker: PhantomData<PllConstants>,
130}
131
132impl<'a, PllConstants: clock_constants::PllConstants> Pll<'a, PllConstants> {
133    // Create a new instance of the PLL clock.
134    //
135    // The instance of the PLL clock is configured to run at 96MHz and with minimal PLL jitter
136    // effects.
137    //
138    // # Parameters
139    //
140    // + rcc: an instance of [crate::rcc]
141    //
142    // # Returns
143    //
144    // An instance of the PLL clock.
145    pub(in crate::clocks) fn new(rcc: &'a Rcc) -> Self {
146        const PLLP: usize = match DEFAULT_PLLP_VALUE {
147            PLLP::DivideBy2 => 2,
148            PLLP::DivideBy4 => 4,
149            PLLP::DivideBy6 => 6,
150            PLLP::DivideBy8 => 8,
151        };
152        const PLLM: usize = DEFAULT_PLLM_VALUE as usize;
153        const PLLQ: usize = DEFAULT_PLLQ_VALUE as usize;
154        Self {
155            rcc,
156            frequency_mhz: OptionalCell::new(HSI_FREQUENCY_MHZ / PLLM * DEFAULT_PLLN_VALUE / PLLP),
157            pll48_frequency_mhz: OptionalCell::new(
158                HSI_FREQUENCY_MHZ / PLLM * DEFAULT_PLLN_VALUE / PLLQ,
159            ),
160            pll48_calibrated: Cell::new(true),
161            _marker: PhantomData,
162        }
163    }
164
165    // The caller must ensure the desired frequency lies between MIN_FREQ_MHZ and
166    // MAX_FREQ_MHZ.  Otherwise, the return value makes no sense.
167    fn compute_pllp(desired_frequency_mhz: usize) -> PLLP {
168        if desired_frequency_mhz < 55 {
169            PLLP::DivideBy8
170        } else if desired_frequency_mhz < 73 {
171            PLLP::DivideBy6
172        } else if desired_frequency_mhz < 109 {
173            PLLP::DivideBy4
174        } else {
175            PLLP::DivideBy2
176        }
177    }
178
179    // The caller must ensure the desired frequency lies between MIN_FREQ_MHZ and
180    // MAX_FREQ_MHZ. Otherwise, the return value makes no sense.
181    fn compute_plln(
182        desired_frequency_mhz: usize,
183        pll_source_clock_freq: usize,
184        pllp: PLLP,
185    ) -> usize {
186        let vco_input_frequency: usize = pll_source_clock_freq / DEFAULT_PLLM_VALUE as usize;
187        desired_frequency_mhz * Into::<usize>::into(pllp) / vco_input_frequency
188    }
189
190    // The caller must ensure the VCO output frequency lies between 100 and 432MHz. Otherwise, the
191    // return value makes no sense.
192    fn compute_pllq(vco_output_frequency_mhz: usize) -> PLLQ {
193        for pllq in 3..10 {
194            if 48 * pllq >= vco_output_frequency_mhz {
195                return match pllq {
196                    3 => PLLQ::DivideBy3,
197                    4 => PLLQ::DivideBy4,
198                    5 => PLLQ::DivideBy5,
199                    6 => PLLQ::DivideBy6,
200                    7 => PLLQ::DivideBy7,
201                    8 => PLLQ::DivideBy8,
202                    _ => PLLQ::DivideBy9,
203                };
204            }
205        }
206        unreachable!("The previous for loop should always return");
207    }
208
209    /// Set the PLL source clock
210    fn set_pll_source_clock(&self, source: PllSource) -> Result<(), ErrorCode> {
211        if self.is_enabled() {
212            Err(ErrorCode::FAIL)
213        } else {
214            self.rcc.set_pll_clocks_source(source);
215            Ok(())
216        }
217    }
218
219    /// Start the PLL clock.
220    ///
221    /// # Errors
222    ///
223    /// + [Err]\([ErrorCode::BUSY]\): if enabling the PLL clock took too long. Recall this method to
224    /// ensure the PLL clock is running.
225    pub fn enable(&self) -> Result<(), ErrorCode> {
226        // Enable the PLL clock
227        self.rcc.enable_pll_clock();
228
229        // Wait until the PLL clock is locked.
230        // 200 was obtained by running tests in release mode
231        for _ in 0..200 {
232            if self.rcc.is_locked_pll_clock() {
233                return Ok(());
234            }
235        }
236
237        // If waiting for the PLL clock took too long, return ErrorCode::BUSY
238        Err(ErrorCode::BUSY)
239    }
240
241    /// Stop the PLL clock.
242    ///
243    /// # Errors
244    ///
245    /// + [Err]\([ErrorCode::FAIL]\): if the PLL clock is configured as the system clock.
246    /// + [Err]\([ErrorCode::BUSY]\): disabling the PLL clock took to long. Retry to ensure it is
247    /// not running.
248    pub fn disable(&self) -> Result<(), ErrorCode> {
249        // Can't disable the PLL clock when it is used as the system clock
250        if self.rcc.get_sys_clock_source() == SysClockSource::PLL {
251            return Err(ErrorCode::FAIL);
252        }
253
254        // Disable the PLL clock
255        self.rcc.disable_pll_clock();
256
257        // Wait to unlock the PLL clock
258        // 10 was obtained by testing in release mode
259        for _ in 0..10 {
260            if !self.rcc.is_locked_pll_clock() {
261                return Ok(());
262            }
263        }
264
265        // If the waiting was too long, return ErrorCode::BUSY
266        Err(ErrorCode::BUSY)
267    }
268
269    /// Check whether the PLL clock is enabled or not.
270    ///
271    /// # Returns
272    ///
273    /// + [false]: the PLL clock is not enabled
274    /// + [true]: the PLL clock is enabled
275    pub fn is_enabled(&self) -> bool {
276        self.rcc.is_enabled_pll_clock()
277    }
278
279    /// Set the frequency of the PLL clock.
280    ///
281    /// The PLL clock has two outputs:
282    ///
283    /// + main output used for configuring the system clock
284    /// + a second output called PLL48CLK used by OTG USB FS (48MHz), the random number generator
285    /// (≤ 48MHz) and the SDIO (≤ 48MHz) clocks.
286    ///
287    /// When calling this method, the given frequency is set for the main output. The method will
288    /// attempt to configure the PLL48CLK output to 48MHz, or to the highest value less than 48MHz
289    /// if it is not possible to get a precise 48MHz. In order to obtain a precise 48MHz frequency
290    /// (for the OTG USB FS peripheral), one should call this method with a frequency of 1, 1.5, 2,
291    /// 2.5 ... 4 x 48MHz.
292    ///
293    /// # Parameters
294    ///
295    /// + pll_source: PLL source clock (HSI or HSE)
296    ///
297    /// + source_frequency: the frequency of the PLL source clock in MHz. For the HSI the frequency
298    /// is fixed to 16MHz. For the HSE, the frequency is hardware-dependent
299    ///
300    /// + desired_frequency_mhz: the desired frequency in MHz. Supported values: 24-216MHz for
301    /// STM32F401 and 13-216MHz for all the other chips
302    ///
303    /// # Errors
304    ///
305    /// + [Err]\([ErrorCode::INVAL]\): if the desired frequency can't be achieved
306    /// + [Err]\([ErrorCode::FAIL]\): if the PLL clock is already enabled. It must be disabled before
307    /// configuring it.
308    pub(super) fn set_frequency_mhz(
309        &self,
310        pll_source: PllSource,
311        source_frequency: usize,
312        desired_frequency_mhz: usize,
313    ) -> Result<(), ErrorCode> {
314        // Check for errors:
315        // + PLL clock running
316        // + invalid frequency
317        if self.rcc.is_enabled_pll_clock() {
318            return Err(ErrorCode::FAIL);
319        } else if desired_frequency_mhz < PllConstants::MIN_FREQ_MHZ
320            || desired_frequency_mhz > PllConstants::MAX_FREQ_MHZ
321        {
322            return Err(ErrorCode::INVAL);
323        }
324
325        // The output frequencies for the PLL clock is computed as following:
326        // Source frequency / PLLM = VCO input frequency (must range from 1MHz to 2MHz)
327        // VCO output frequency = VCO input frequency * PLLN (must range from 100MHz to 432MHz)
328        // PLL output frequency = VCO output frequency / PLLP
329        // PLL48CLK = VCO output frequency / PLLQ
330
331        // Set PLL source (HSI or HSE)
332        if self.set_pll_source_clock(pll_source) != Ok(()) {
333            return Err(ErrorCode::FAIL);
334        }
335
336        // Compute PLLP
337        let pllp = Self::compute_pllp(desired_frequency_mhz);
338        self.rcc.set_pll_clock_p_divider(pllp);
339
340        // Compute PLLN
341        let plln = Self::compute_plln(desired_frequency_mhz, source_frequency, pllp);
342        self.rcc.set_pll_clock_n_multiplier(plln);
343
344        // Compute PLLQ
345        let vco_output_frequency = source_frequency / DEFAULT_PLLM_VALUE as usize * plln;
346        let pllq = Self::compute_pllq(vco_output_frequency);
347        self.rcc.set_pll_clock_q_divider(pllq);
348
349        // Check if PLL48CLK is calibrated, e.g. its frequency is exactly 48MHz
350        let pll48_frequency = vco_output_frequency / pllq as usize;
351        self.pll48_calibrated
352            .set(pll48_frequency == 48 && vco_output_frequency % pllq as usize == 0);
353
354        // Cache the frequency so it is not computed every time a get method is called
355        self.frequency_mhz.set(desired_frequency_mhz);
356        self.pll48_frequency_mhz.set(pll48_frequency);
357
358        Ok(())
359    }
360
361    /// Get the frequency in MHz of the PLL clock.
362    ///
363    /// # Returns
364    ///
365    /// + [Some]\(frequency_mhz\): if the PLL clock is enabled.
366    /// + [None]: if the PLL clock is disabled.
367    pub fn get_frequency_mhz(&self) -> Option<usize> {
368        if self.is_enabled() {
369            self.frequency_mhz.get()
370        } else {
371            None
372        }
373    }
374
375    /// Get the frequency in MHz of the PLL clock from RCC registers instead of using the cached
376    /// value.
377    ///
378    /// # Returns
379    ///
380    /// + [Some]\(frequency_mhz\): if the PLL clock is enabled.
381    /// + [None]: if the PLL clock is disabled.
382    pub fn get_frequency_mhz_no_cache(&self, source_frequency: usize) -> Option<usize> {
383        if self.is_enabled() {
384            let pllm = self.rcc.get_pll_clocks_m_divider() as usize;
385            let plln = self.rcc.get_pll_clock_n_multiplier();
386            let pllp: usize = self.rcc.get_pll_clock_p_divider().into();
387            Some(source_frequency / pllm * plln / pllp)
388        } else {
389            None
390        }
391    }
392
393    /// Get the frequency in MHz of the PLL48 clock.
394    ///
395    /// **NOTE:** If the PLL clock was not configured with a frequency multiple of 48MHz, the
396    /// returned value is inaccurate.
397    ///
398    /// # Returns
399    ///
400    /// + [Some]\(frequency_mhz\): if the PLL clock is enabled.
401    /// + [None]: if the PLL clock is disabled.
402    pub fn get_frequency_mhz_pll48(&self) -> Option<usize> {
403        if self.is_enabled() {
404            self.pll48_frequency_mhz.get()
405        } else {
406            None
407        }
408    }
409
410    /// Check if the PLL48 clock is calibrated (its output is exactly 48MHz).
411    ///
412    /// A frequency of 48MHz is required for USB OTG FS.
413    ///
414    /// # Returns
415    ///
416    /// + [true]: the PLL48 clock frequency is exactly 48MHz.
417    /// + [false]: the PLL48 clock is not exactly 48MHz.
418    pub fn is_pll48_calibrated(&self) -> bool {
419        self.pll48_calibrated.get()
420    }
421}
422
423/// Tests for the PLL clock
424///
425/// This module ensures that the PLL clock works as expected. If changes are brought to the PLL
426/// clock, ensure to run all the tests to see if anything is broken.
427///
428/// # Usage
429///
430/// First, import the [crate::clocks::pll] module inside the board main file:
431///
432/// ```rust,ignore
433/// use stm32f429zi::pll;
434/// ```
435/// To run all the available tests, add this line before **kernel::process::load_processes()**:
436///
437/// ```rust,ignore
438/// pll::tests::run(&peripherals.stm32f4.clocks.pll);
439/// ```
440///
441/// If everything works as expected, the following message should be printed on the kernel console:
442///
443/// ```text
444/// ===============================================
445/// Testing PLL...
446/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
447/// Testing PLL configuration...
448/// Finished testing PLL configuration.
449/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
450/// Testing PLL struct...
451/// Finished testing PLL struct.
452/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
453/// Finished testing PLL. Everything is alright!
454/// ===============================================
455/// ```
456///
457/// There is also the possibility to run a part of the test suite. Check the functions present in
458/// this module for more details.
459///
460/// # Errors
461///
462/// If there are any errors, open an issue ticket at <https://github.com/tock/tock>. Please provide the
463/// output of the test execution.
464pub mod tests {
465    use super::{
466        clock_constants, debug, ErrorCode, Pll, PllSource, DEFAULT_PLLM_VALUE, HSI_FREQUENCY_MHZ,
467        PLLM, PLLP, PLLQ,
468    };
469
470    // Depending on the default PLLM value, the computed PLLN value changes.
471    const MULTIPLIER: usize = match DEFAULT_PLLM_VALUE {
472        PLLM::DivideBy8 => 1,
473        PLLM::DivideBy16 => 2,
474    };
475
476    /// Test if the configuration parameters are correctly computed for a given frequency.
477    ///
478    /// # Usage
479    ///
480    /// ```rust,ignore
481    /// use stm32f429zi::pll; // Import the pll module
482    /// /* Code goes here */
483    /// pll::test::test_pll_config(&peripherals.stm32f4.pll); // Run the tests
484    /// ```
485    pub fn test_pll_config<PllConstants: clock_constants::PllConstants>() {
486        debug!("Testing PLL configuration...");
487
488        // 13 or 24MHz --> minimum value
489        let mut pllp = Pll::<PllConstants>::compute_pllp(PllConstants::MIN_FREQ_MHZ);
490        assert_eq!(PLLP::DivideBy8, pllp);
491        let mut plln =
492            Pll::<PllConstants>::compute_plln(PllConstants::MIN_FREQ_MHZ, HSI_FREQUENCY_MHZ, pllp);
493
494        #[cfg(not(feature = "stm32f401"))]
495        assert_eq!(52 * MULTIPLIER, plln);
496        #[cfg(feature = "stm32f401")]
497        assert_eq!(96 * MULTIPLIER, plln);
498
499        let mut vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
500        let mut pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
501
502        #[cfg(not(feature = "stm32f401"))]
503        assert_eq!(PLLQ::DivideBy3, pllq);
504        #[cfg(feature = "stm32f401")]
505        assert_eq!(PLLQ::DivideBy4, pllq);
506
507        // 25MHz --> minimum required value for Ethernet devices
508        pllp = Pll::<PllConstants>::compute_pllp(25);
509        assert_eq!(PLLP::DivideBy8, pllp);
510        plln = Pll::<PllConstants>::compute_plln(25, HSI_FREQUENCY_MHZ, pllp);
511        assert_eq!(100 * MULTIPLIER, plln);
512        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
513        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
514        assert_eq!(PLLQ::DivideBy5, pllq);
515
516        // 54MHz --> last frequency before PLLP becomes DivideBy6
517        pllp = Pll::<PllConstants>::compute_pllp(54);
518        assert_eq!(PLLP::DivideBy8, pllp);
519        plln = Pll::<PllConstants>::compute_plln(54, HSI_FREQUENCY_MHZ, pllp);
520        assert_eq!(216 * MULTIPLIER, plln);
521        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
522        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
523        assert_eq!(PLLQ::DivideBy9, pllq);
524
525        // 55MHz --> PLLP becomes DivideBy6
526        pllp = Pll::<PllConstants>::compute_pllp(55);
527        assert_eq!(PLLP::DivideBy6, pllp);
528        plln = Pll::<PllConstants>::compute_plln(55, HSI_FREQUENCY_MHZ, pllp);
529        assert_eq!(165 * MULTIPLIER, plln);
530        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
531        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
532        assert_eq!(PLLQ::DivideBy7, pllq);
533
534        // 70MHz --> Another value for PLLP::DivideBy6
535        pllp = Pll::<PllConstants>::compute_pllp(70);
536        assert_eq!(PLLP::DivideBy6, pllp);
537        plln = Pll::<PllConstants>::compute_plln(70, HSI_FREQUENCY_MHZ, pllp);
538        assert_eq!(210 * MULTIPLIER, plln);
539        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
540        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
541        assert_eq!(PLLQ::DivideBy9, pllq);
542
543        // 72MHz --> last frequency before PLLP becomes DivideBy4
544        pllp = Pll::<PllConstants>::compute_pllp(72);
545        assert_eq!(PLLP::DivideBy6, pllp);
546        plln = Pll::<PllConstants>::compute_plln(72, HSI_FREQUENCY_MHZ, pllp);
547        assert_eq!(216 * MULTIPLIER, plln);
548        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
549        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
550        assert_eq!(PLLQ::DivideBy9, pllq);
551
552        // 73MHz --> PLLP becomes DivideBy4
553        pllp = Pll::<PllConstants>::compute_pllp(73);
554        assert_eq!(PLLP::DivideBy4, pllp);
555        plln = Pll::<PllConstants>::compute_plln(73, HSI_FREQUENCY_MHZ, pllp);
556        assert_eq!(146 * MULTIPLIER, plln);
557        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
558        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
559        assert_eq!(PLLQ::DivideBy7, pllq);
560
561        // 100MHz --> Another value for PLLP::DivideBy4
562        pllp = Pll::<PllConstants>::compute_pllp(100);
563        assert_eq!(PLLP::DivideBy4, pllp);
564        plln = Pll::<PllConstants>::compute_plln(100, HSI_FREQUENCY_MHZ, pllp);
565        assert_eq!(200 * MULTIPLIER, plln);
566        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
567        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
568        assert_eq!(PLLQ::DivideBy9, pllq);
569
570        // 108MHz --> last frequency before PLLP becomes DivideBy2
571        pllp = Pll::<PllConstants>::compute_pllp(108);
572        assert_eq!(PLLP::DivideBy4, pllp);
573        plln = Pll::<PllConstants>::compute_plln(108, HSI_FREQUENCY_MHZ, pllp);
574        assert_eq!(216 * MULTIPLIER, plln);
575        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
576        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
577        assert_eq!(PLLQ::DivideBy9, pllq);
578
579        // 109MHz --> PLLP becomes DivideBy2
580        pllp = Pll::<PllConstants>::compute_pllp(109);
581        assert_eq!(PLLP::DivideBy2, pllp);
582        plln = Pll::<PllConstants>::compute_plln(109, HSI_FREQUENCY_MHZ, pllp);
583        assert_eq!(109 * MULTIPLIER, plln);
584        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
585        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
586        assert_eq!(PLLQ::DivideBy5, pllq);
587
588        // 125MHz --> Another value for PLLP::DivideBy2
589        pllp = Pll::<PllConstants>::compute_pllp(125);
590        assert_eq!(PLLP::DivideBy2, pllp);
591        plln = Pll::<PllConstants>::compute_plln(125, HSI_FREQUENCY_MHZ, pllp);
592        assert_eq!(125 * MULTIPLIER, plln);
593        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
594        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
595        assert_eq!(PLLQ::DivideBy6, pllq);
596
597        // 180MHz --> Max frequency for the CPU
598        pllp = Pll::<PllConstants>::compute_pllp(180);
599        assert_eq!(PLLP::DivideBy2, pllp);
600        plln = Pll::<PllConstants>::compute_plln(180, HSI_FREQUENCY_MHZ, pllp);
601        assert_eq!(180 * MULTIPLIER, plln);
602        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
603        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
604        assert_eq!(PLLQ::DivideBy8, pllq);
605
606        // 216MHz --> Max frequency for the PLL due to the VCO output frequency limit
607        pllp = Pll::<PllConstants>::compute_pllp(216);
608        assert_eq!(PLLP::DivideBy2, pllp);
609        plln = Pll::<PllConstants>::compute_plln(216, HSI_FREQUENCY_MHZ, pllp);
610        assert_eq!(216 * MULTIPLIER, plln);
611        vco_output_frequency_mhz = HSI_FREQUENCY_MHZ / DEFAULT_PLLM_VALUE as usize * plln;
612        pllq = Pll::<PllConstants>::compute_pllq(vco_output_frequency_mhz);
613        assert_eq!(PLLQ::DivideBy9, pllq);
614
615        debug!("Finished testing PLL configuration.");
616    }
617
618    /// Check if the PLL works as expected.
619    ///
620    /// **NOTE:** it is highly recommended to call [test_pll_config]
621    /// first to check whether the configuration parameters are correctly computed.
622    ///
623    /// # Usage
624    ///
625    /// ```rust,ignore
626    /// use stm32f429zi::pll; // Import the PLL module
627    /// /* Code goes here */
628    /// pll::test::test_pll_struct(&peripherals.stm32f4.pll); // Run the tests
629    /// ```
630    pub fn test_pll_struct<'a, PllConstants: clock_constants::PllConstants>(
631        pll: &'a Pll<'a, PllConstants>,
632    ) {
633        debug!("Testing PLL struct...");
634        // Make sure the PLL clock is disabled
635        assert_eq!(Ok(()), pll.disable());
636        assert!(!pll.is_enabled());
637
638        // Attempting to configure the PLL with either too high or too low frequency
639        assert_eq!(
640            Err(ErrorCode::INVAL),
641            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 12)
642        );
643        assert_eq!(
644            Err(ErrorCode::INVAL),
645            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 217)
646        );
647
648        // Start the PLL with the default configuration.
649        assert_eq!(Ok(()), pll.enable());
650
651        // Make sure the PLL is enabled.
652        assert!(pll.is_enabled());
653
654        // By default, the PLL clock is set to 96MHz
655        assert_eq!(Some(96), pll.get_frequency_mhz());
656
657        // By default, the PLL48 clock is correctly calibrated
658        assert!(pll.is_pll48_calibrated());
659
660        // Impossible to configure the PLL clock once it is enabled.
661        assert_eq!(
662            Err(ErrorCode::FAIL),
663            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 50)
664        );
665
666        // Stop the PLL in order to reconfigure it.
667        assert_eq!(Ok(()), pll.disable());
668
669        // Configure the PLL clock to run at 25MHz
670        assert_eq!(
671            Ok(()),
672            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 25)
673        );
674
675        // Start the PLL with the new configuration
676        assert_eq!(Ok(()), pll.enable());
677
678        // get_frequency() method should reflect the new change
679        assert_eq!(Some(25), pll.get_frequency_mhz());
680
681        // Since 25 is not a multiple of 48, the PLL48 clock is not correctly calibrated
682        assert!(!pll.is_pll48_calibrated());
683
684        // The expected PLL48 clock value in this case should be approximately 40 MHz.
685        // It is actually exactly 40MHz in this particular case.
686        assert_eq!(Some(40), pll.get_frequency_mhz_pll48());
687
688        // Stop the PLL clock
689        assert_eq!(Ok(()), pll.disable());
690
691        // Attempting to get the frequency of the PLL clock when it is disabled should return None.
692        assert_eq!(None, pll.get_frequency_mhz());
693        // Same for PLL48 clock
694        assert_eq!(None, pll.get_frequency_mhz_pll48());
695
696        // Attempting to configure the PLL clock with a frequency multiple of 48MHz
697        assert_eq!(
698            Ok(()),
699            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 144)
700        );
701        assert_eq!(Ok(()), pll.enable());
702        assert_eq!(Some(144), pll.get_frequency_mhz());
703
704        // PLL48 clock output should be correctly calibrated
705        assert!(pll.is_pll48_calibrated());
706        assert_eq!(Some(48), pll.get_frequency_mhz_pll48());
707
708        // Reconfigure the clock for 100MHz
709        assert_eq!(Ok(()), pll.disable());
710        assert_eq!(
711            Ok(()),
712            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 100)
713        );
714        assert_eq!(Ok(()), pll.enable());
715        assert_eq!(Some(100), pll.get_frequency_mhz());
716
717        // In this case, the PLL48 clock is not correctly calibrated. Its frequency is
718        // approximately 44MHz.
719        assert!(!pll.is_pll48_calibrated());
720        assert_eq!(Some(44), pll.get_frequency_mhz_pll48());
721
722        // Configure the clock to 72MHz = 48MHz * 1.5
723        assert_eq!(Ok(()), pll.disable());
724        assert_eq!(
725            Ok(()),
726            pll.set_frequency_mhz(PllSource::HSI, HSI_FREQUENCY_MHZ, 72)
727        );
728        assert_eq!(Ok(()), pll.enable());
729        assert_eq!(Some(72), pll.get_frequency_mhz());
730
731        // In this case, the PLL48 clock is correctly calibrated
732        assert!(pll.is_pll48_calibrated());
733        assert_eq!(Some(48), pll.get_frequency_mhz_pll48());
734
735        // Turn off the PLL clock
736        assert_eq!(Ok(()), pll.disable());
737        assert!(!pll.is_enabled());
738
739        debug!("Finished testing PLL struct.");
740    }
741
742    /// Run the entire test suite.
743    ///
744    /// # Usage
745    ///
746    /// ```rust,ignore
747    /// use stm32f429zi::pll; // Import the PLL module
748    /// /* Code goes here */
749    /// pll::test::run(&peripherals.stm32f4.pll); // Run the tests
750    /// ```
751    pub fn run<'a, PllConstants: clock_constants::PllConstants>(pll: &'a Pll<'a, PllConstants>) {
752        debug!("");
753        debug!("===============================================");
754        debug!("Testing PLL...");
755        debug!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
756        test_pll_config::<PllConstants>();
757        debug!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
758        test_pll_struct(pll);
759        debug!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
760        debug!("Finished testing PLL. Everything is alright!");
761        debug!("===============================================");
762        debug!("");
763    }
764}