stm32f4xx/clocks/
hse.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 Tock Contributors 2022.
4
5//! HSE (high-speed external) clock driver for the STM32F4xx family. [^doc_ref]
6//!
7//! # Usage
8//!
9//! For the purposes of brevity, any error checking has been removed. In real applications, always
10//! check the return values of the [Hse] methods.
11//!
12//! First, get a reference to the [Hse] struct:
13//! ```rust,ignore
14//! let hse = &base_peripherals.clocks.hse;
15//! ```
16//!
17//! ## Start the clock
18//!
19//! ```rust,ignore
20//! hse.enable(stm32f429zi::rcc::HseMode::BYPASS);
21//! ```
22//!
23//! ## Set the clock frequency
24//! ```rust,ignore
25//! hse.set_frequency_mhz(8);
26//! ```
27//!
28//! ## Stop the clock
29//!
30//! ```rust,ignore
31//! hse.disable();
32//! ```
33//!
34//! ## Check if the clock is enabled
35//! ```rust,ignore
36//! if hse.is_enabled() {
37//!     /* Do something */
38//! } else {
39//!     /* Do something */
40//! }
41//! ```
42//!
43//! ## Get the frequency of the clock
44//! ```rust,ignore
45//! let hse_frequency_mhz = hse.get_frequency_mhz().unwrap();
46//! ```
47//!
48//! [^doc_ref]: See 6.2.1 in the documentation.
49
50use crate::rcc::HseMode;
51use crate::rcc::Rcc;
52
53use kernel::debug;
54use kernel::utilities::cells::OptionalCell;
55use kernel::ErrorCode;
56
57/// Main HSE clock structure
58pub struct Hse<'a> {
59    rcc: &'a Rcc,
60    hse_frequency_mhz: OptionalCell<usize>,
61}
62
63impl<'a> Hse<'a> {
64    /// Create a new instance of the HSE clock.
65    ///
66    /// # Parameters
67    ///
68    /// + rcc: an instance of [crate::rcc]
69    ///
70    /// # Returns
71    ///
72    /// An instance of the HSE clock.
73    pub(in crate::clocks) fn new(rcc: &'a Rcc) -> Self {
74        Self {
75            rcc,
76            hse_frequency_mhz: OptionalCell::empty(),
77        }
78    }
79
80    /// Start the HSE clock.
81    ///
82    /// # Errors
83    ///
84    /// + [Err]\([ErrorCode::BUSY]\): disabling the HSE clock took to long. Retry to ensure it is running
85    pub fn enable(&self, source: HseMode) -> Result<(), ErrorCode> {
86        if source == HseMode::BYPASS {
87            self.rcc.enable_hse_clock_bypass();
88        }
89
90        self.rcc.enable_hse_clock();
91
92        for _ in 0..100 {
93            if self.rcc.is_ready_hse_clock() {
94                return Ok(());
95            }
96        }
97
98        Err(ErrorCode::BUSY)
99    }
100
101    /// Stop the HSE clock.
102    ///
103    /// # Errors
104    ///
105    /// + [Err]\([ErrorCode::FAIL]\): if the HSE clock is configured as the system clock.
106    /// + [Err]\([ErrorCode::BUSY]\): disabling the HSE clock took to long. Retry to ensure it is
107    /// not running.
108    pub fn disable(&self) -> Result<(), ErrorCode> {
109        if self.rcc.is_hse_clock_system_clock() {
110            return Err(ErrorCode::FAIL);
111        }
112
113        self.rcc.disable_hse_clock();
114
115        for _ in 0..10 {
116            if !self.rcc.is_ready_hse_clock() {
117                return Ok(());
118            }
119        }
120
121        Err(ErrorCode::BUSY)
122    }
123
124    /// Check whether the HSE clock is enabled or not.
125    ///
126    /// # Returns
127    ///
128    /// + [false]: the HSE clock is not enabled
129    /// + [true]: the HSE clock is enabled
130    pub fn is_enabled(&self) -> bool {
131        self.rcc.is_enabled_hse_clock()
132    }
133
134    /// Get the frequency in MHz of the HSE clock.
135    ///
136    /// # Returns
137    ///
138    /// + [Some]\(frequency_mhz\): if the HSE clock is enabled.
139    /// + [None]: if the HSE clock is disabled.
140    pub fn get_frequency_mhz(&self) -> Option<usize> {
141        if self.is_enabled() {
142            self.hse_frequency_mhz.get()
143        } else {
144            None
145        }
146    }
147
148    /// Set the frequency in MHz of the HSE clock.
149    ///
150    /// # Parameters
151    ///
152    /// + frequency: HSE frequency in MHz
153    pub fn set_frequency_mhz(&self, frequency: usize) {
154        self.hse_frequency_mhz.set(frequency);
155    }
156}
157
158/// Tests for the HSE clock
159///
160/// This module ensures that the HSE clock works as expected. If changes are brought to the HSE
161/// clock, ensure to run all the tests to see if anything is broken.
162///
163/// # Usage
164///
165/// First, import the [crate::clocks::hse] module in the desired board main file:
166///
167/// ```rust,ignore
168/// use stm32f429zi::clocks::hse;
169/// ```
170///
171/// Then, to run the tests, put the following line before [kernel::process::load_processes]:
172///
173/// ```rust,ignore
174/// hse::tests::run(&peripherals.stm32f4.clocks.hse);
175/// ```
176///
177/// If everything works as expected, the following message should be printed on the kernel console:
178///
179/// ```text
180/// ===============================================
181/// Testing HSE...
182/// Finished testing HSE. Everything is alright!
183/// ===============================================
184/// ```
185///
186/// **NOTE:** All these tests assume default boot configuration.
187pub mod tests {
188    use super::{debug, Hse, HseMode};
189
190    /// Run the entire test suite.
191    pub fn run(hse: &Hse) {
192        debug!("");
193        debug!("===============================================");
194        debug!("Testing HSE...");
195
196        // By default, the HSE clock is disabled
197        assert!(!hse.is_enabled());
198
199        // HSE frequency is None
200        assert_eq!(None, hse.get_frequency_mhz());
201
202        // HSE should be enabled
203        assert_eq!(Ok(()), hse.enable(HseMode::BYPASS));
204
205        // HSE frequency is 8MHz
206        assert_eq!(Some(8), hse.get_frequency_mhz());
207
208        // Nothing should happen if the HSE clock is being enabled when already running
209        assert_eq!(Ok(()), hse.enable(HseMode::BYPASS));
210
211        // It is possible to disable the HSE clock since it is not the system clock source
212        assert_eq!(Ok(()), hse.disable());
213
214        debug!("Finished testing HSE. Everything is alright!");
215        debug!("===============================================");
216        debug!("");
217    }
218}