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