nrf52_hal_common/
clocks.rs

1//! Configuration and control of the High and Low Frequency Clock
2//! sources
3
4use crate::target::CLOCK;
5
6// ZST Type States
7
8/// Internal/RC Oscillator
9pub struct Internal;
10
11/// External Crystal Oscillator
12pub struct ExternalOscillator;
13
14/// Low Frequency Clock synthesize from High Frequency Clock
15pub struct LfOscSynthesized;
16
17/// Low Frequency Clock Started
18pub struct LfOscStarted;
19
20/// Low Frequency Clock Stopped
21pub struct LfOscStopped;
22
23/// Extension trait for the CLOCK peripheral
24pub trait ClocksExt {
25    fn constrain(self) -> Clocks<Internal, Internal, LfOscStopped>;
26}
27
28/// High Frequency Clock Frequency (in Hz)
29pub const HFCLK_FREQ: u32 = 64_000_000;
30/// Low Frequency Clock Frequency (in Hz)
31pub const LFCLK_FREQ: u32 = 32_768;
32
33/// A high level abstraction for the CLOCK peripheral
34pub struct Clocks<H, L, LSTAT> {
35    hfclk: H,
36    lfclk: L,
37    lfstat: LSTAT,
38    periph: CLOCK,
39}
40
41impl<H, L, LSTAT> Clocks<H, L, LSTAT> {
42    /// Use an external oscillator as the high frequency clock source
43    pub fn enable_ext_hfosc(self) -> Clocks<ExternalOscillator, L, LSTAT> {
44        self.periph.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
45
46        // Datasheet says this is likely to take 0.36ms
47        while self.periph.events_hfclkstarted.read().bits() != 1 {}
48        self.periph
49            .events_hfclkstarted
50            .write(|w| unsafe { w.bits(0) });
51
52        Clocks {
53            hfclk: ExternalOscillator,
54            lfclk: self.lfclk,
55            lfstat: self.lfstat,
56            periph: self.periph,
57        }
58    }
59
60    /// Use the internal oscillator as the high frequency clock source
61    pub fn disable_ext_hfosc(self) -> Clocks<Internal, L, LSTAT> {
62        self.periph.tasks_hfclkstop.write(|w| unsafe { w.bits(1) });
63        Clocks {
64            hfclk: Internal,
65            lfclk: self.lfclk,
66            lfstat: self.lfstat,
67            periph: self.periph,
68        }
69    }
70
71    /// Start the Low Frequency clock
72    pub fn start_lfclk(self) -> Clocks<H, L, LfOscStarted> {
73        self.periph.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
74
75        // Datasheet says this could take 100us from synth source
76        // 600us from rc source, 0.25s from an external source
77        while self.periph.events_lfclkstarted.read().bits() != 1 {}
78        self.periph
79            .events_lfclkstarted
80            .write(|w| unsafe { w.bits(0) });
81
82        Clocks {
83            hfclk: self.hfclk,
84            lfclk: self.lfclk,
85            lfstat: LfOscStarted,
86            periph: self.periph,
87        }
88    }
89}
90
91/// Allowable configuration options for the low frequency oscillator when
92/// driven fron an external crystal
93pub enum LfOscConfiguration {
94    NoExternalNoBypass,
95    ExternalNoBypass,
96    ExternalAndBypass,
97}
98
99impl<H, L> Clocks<H, L, LfOscStarted> {
100    /// Stop the Low Frequency clock
101    pub fn stop_lfclk(self) -> Clocks<H, L, LfOscStopped> {
102        self.periph.tasks_lfclkstop.write(|w| unsafe { w.bits(1) });
103        Clocks {
104            hfclk: self.hfclk,
105            lfclk: self.lfclk,
106            lfstat: LfOscStopped,
107            periph: self.periph,
108        }
109    }
110}
111
112impl<H, L> Clocks<H, L, LfOscStopped> {
113    /// Use the internal RC Oscillator for the low frequency clock source
114    pub fn set_lfclk_src_rc(self) -> Clocks<H, Internal, LfOscStopped> {
115        self.periph
116            .lfclksrc
117            .write(|w| w.src().rc().bypass().disabled().external().disabled());
118        Clocks {
119            hfclk: self.hfclk,
120            lfclk: Internal,
121            lfstat: self.lfstat,
122            periph: self.periph,
123        }
124    }
125
126    /// Generate the Low Frequency clock from the high frequency clock source
127    pub fn set_lfclk_src_synth(self) -> Clocks<H, LfOscSynthesized, LfOscStopped> {
128        self.periph
129            .lfclksrc
130            .write(|w| w.src().synth().bypass().disabled().external().disabled());
131        Clocks {
132            hfclk: self.hfclk,
133            lfclk: LfOscSynthesized,
134            lfstat: self.lfstat,
135            periph: self.periph,
136        }
137    }
138
139    /// Use an external crystal to drive the low frequency clock
140    pub fn set_lfclk_src_external(
141        self,
142        cfg: LfOscConfiguration,
143    ) -> Clocks<H, ExternalOscillator, LfOscStopped> {
144        let (ext, byp) = match cfg {
145            LfOscConfiguration::NoExternalNoBypass => (false, false),
146            LfOscConfiguration::ExternalNoBypass => (true, false),
147            LfOscConfiguration::ExternalAndBypass => (true, true),
148        };
149        self.periph
150            .lfclksrc
151            .write(move |w| w.src().xtal().bypass().bit(byp).external().bit(ext));
152        Clocks {
153            hfclk: self.hfclk,
154            lfclk: ExternalOscillator,
155            lfstat: self.lfstat,
156            periph: self.periph,
157        }
158    }
159}
160
161impl ClocksExt for CLOCK {
162    fn constrain(self) -> Clocks<Internal, Internal, LfOscStopped> {
163        Clocks {
164            hfclk: Internal,
165            lfclk: Internal,
166            lfstat: LfOscStopped,
167            periph: self,
168        }
169    }
170}