Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Commit 04cfe50

Browse files
authored
Merge pull request #45 from arjanmels/feature-clock-improvements
Clock Improvements
2 parents a5e8e9e + 1db111e commit 04cfe50

File tree

5 files changed

+156
-54
lines changed

5 files changed

+156
-54
lines changed

examples/multicore.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,6 @@ fn main() -> ! {
8989

9090
writeln!(uart0, "Stack Pointer Core 0: {:08x?}", get_stack_pointer()).unwrap();
9191

92-
// register callback which is called when the clock is switched
93-
clock_control_config
94-
.add_callback(&|| {
95-
let clock_control_config = ClockControlConfig {};
96-
dprintln!(
97-
" Change Clock: CPU: {}, PLL: {}, APB: {}, REF: {}",
98-
clock_control_config.cpu_frequency(),
99-
clock_control_config.pll_frequency(),
100-
clock_control_config.apb_frequency(),
101-
clock_control_config.ref_frequency(),
102-
)
103-
})
104-
.unwrap();
105-
10692
// uncomment next line to test panic exit
10793
// panic!("panic test");
10894

examples/rtccntl.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use core::panic::PanicInfo;
66

77
use esp32_hal::prelude::*;
88

9-
use esp32_hal::clock_control::{sleep, CPUSource, ClockControl, ClockControlConfig};
9+
use esp32_hal::clock_control::{sleep, CPUSource, ClockControl};
1010
use esp32_hal::dport::Split;
1111
use esp32_hal::dprintln;
1212
use esp32_hal::serial::{config::Config, Serial};
@@ -88,15 +88,21 @@ fn main() -> ! {
8888

8989
// register callback which is called when the clock is switched
9090
clock_control_config
91-
.add_callback(&|| {
92-
let clock_control_config = ClockControlConfig {};
91+
.add_callback(&|before_source,
92+
before_freq,
93+
before_apb_freq,
94+
after_source,
95+
after_freq,
96+
after_apb_freq| {
9397
dprintln!(
94-
" Change Clock: CPU: {}, PLL: {}, APB: {}, REF: {}",
95-
clock_control_config.cpu_frequency(),
96-
clock_control_config.pll_frequency(),
97-
clock_control_config.apb_frequency(),
98-
clock_control_config.ref_frequency(),
99-
)
98+
" Before: Source: {:?}, CPU: {}, APB: {}, After: Source: {:?}, CPU: {}, APB: {}",
99+
before_source,
100+
before_freq,
101+
before_apb_freq,
102+
after_source,
103+
after_freq,
104+
after_apb_freq
105+
);
100106
})
101107
.unwrap();
102108

src/clock_control/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl<'a> super::ClockControlConfig {
146146
// TODO: at the moment only static lifetime callbacks are allow
147147
pub fn add_callback<F>(&self, f: &'static F) -> Result<(), Error>
148148
where
149-
F: Fn(),
149+
F: Fn(super::CPUSource, Hertz, Hertz, super::CPUSource, Hertz, Hertz),
150150
{
151151
unsafe { CLOCK_CONTROL.as_mut().unwrap().add_callback(f) }
152152
}

src/clock_control/dfs.rs

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ static DFS_MUTEX: CriticalSectionSpinLockMutex<Locks> = CriticalSectionSpinLockM
2727

2828
/// DFS structure
2929
pub(super) struct DFS {
30-
callbacks: [&'static dyn Fn(); MAX_CALLBACKS],
30+
callbacks: [&'static dyn Fn(super::CPUSource, Hertz, Hertz, super::CPUSource, Hertz, Hertz);
31+
MAX_CALLBACKS],
3132
nr_callbacks: CriticalSectionSpinLockMutex<usize>,
3233
}
3334

3435
impl DFS {
3536
pub(crate) fn new() -> Self {
3637
DFS {
37-
callbacks: [&|| {}; MAX_CALLBACKS],
38+
callbacks: [&|_, _, _, _, _, _| {}; MAX_CALLBACKS],
3839

3940
nr_callbacks: CriticalSectionSpinLockMutex::new(0),
4041
}
@@ -105,13 +106,35 @@ impl<'a> Drop for LockPllD2 {
105106

106107
impl<'a> super::ClockControl {
107108
/// call all the callbacks
108-
fn do_callbacks(&self) {
109+
fn do_callbacks(
110+
&self,
111+
cpu_source_before: super::CPUSource,
112+
cpu_frequency_before: Hertz,
113+
apb_frequency_before: Hertz,
114+
cpu_source_after: super::CPUSource,
115+
cpu_frequency_after: Hertz,
116+
apb_frequency_after: Hertz,
117+
) {
118+
if cpu_source_after == cpu_source_before
119+
&& cpu_frequency_after == cpu_frequency_before
120+
&& apb_frequency_after == apb_frequency_before
121+
{
122+
return;
123+
}
124+
109125
// copy the callbacks to prevent needing to have interrupts disabled the entire time
110126
// as callback cannot be deleted this is ok.
111127
let (nr, callbacks) = (&self.dfs.nr_callbacks).lock(|nr| (*nr, self.dfs.callbacks));
112128

113129
for i in 0..nr {
114-
callbacks[i]();
130+
callbacks[i](
131+
cpu_source_before,
132+
cpu_frequency_before,
133+
apb_frequency_before,
134+
cpu_source_after,
135+
cpu_frequency_after,
136+
apb_frequency_after,
137+
);
115138
}
116139
}
117140

@@ -122,8 +145,20 @@ impl<'a> super::ClockControl {
122145

123146
if data.cpu == 1 {
124147
if data.apb == 0 || self.cpu_frequency_locked > self.cpu_frequency_apb_locked {
148+
let cpu_source_before = self.cpu_source;
149+
let cpu_frequency_before = self.cpu_frequency;
150+
let apb_frequency_before = self.apb_frequency;
151+
125152
self.set_cpu_frequency_locked(data.pll_d2 > 0).unwrap();
126-
self.do_callbacks()
153+
154+
self.do_callbacks(
155+
cpu_source_before,
156+
cpu_frequency_before,
157+
apb_frequency_before,
158+
self.cpu_source,
159+
self.cpu_frequency,
160+
self.apb_frequency,
161+
);
127162
}
128163
}
129164
});
@@ -136,12 +171,24 @@ impl<'a> super::ClockControl {
136171
data.cpu -= 1;
137172

138173
if data.cpu == 0 {
174+
let cpu_source_before = self.cpu_source;
175+
let cpu_frequency_before = self.cpu_frequency;
176+
let apb_frequency_before = self.apb_frequency;
177+
139178
if data.apb == 0 {
140179
self.set_cpu_frequency_default(data.pll_d2 > 0).unwrap();
141180
} else {
142181
self.set_cpu_frequency_apb_locked(data.pll_d2 > 0).unwrap();
143182
}
144-
self.do_callbacks()
183+
184+
self.do_callbacks(
185+
cpu_source_before,
186+
cpu_frequency_before,
187+
apb_frequency_before,
188+
self.cpu_source,
189+
self.cpu_frequency,
190+
self.apb_frequency,
191+
);
145192
}
146193
});
147194
}
@@ -153,8 +200,20 @@ impl<'a> super::ClockControl {
153200

154201
if data.apb == 1 {
155202
if data.cpu == 0 || self.cpu_frequency_apb_locked > self.cpu_frequency_locked {
203+
let cpu_source_before = self.cpu_source;
204+
let cpu_frequency_before = self.cpu_frequency;
205+
let apb_frequency_before = self.apb_frequency;
206+
156207
self.set_cpu_frequency_apb_locked(data.pll_d2 > 0).unwrap();
157-
self.do_callbacks();
208+
209+
self.do_callbacks(
210+
cpu_source_before,
211+
cpu_frequency_before,
212+
apb_frequency_before,
213+
self.cpu_source,
214+
self.cpu_frequency,
215+
self.apb_frequency,
216+
);
158217
}
159218
}
160219
});
@@ -167,12 +226,24 @@ impl<'a> super::ClockControl {
167226
data.apb -= 1;
168227

169228
if data.apb == 0 {
229+
let cpu_source_before = self.cpu_source;
230+
let cpu_frequency_before = self.cpu_frequency;
231+
let apb_frequency_before = self.apb_frequency;
232+
170233
if data.cpu == 0 {
171234
self.set_cpu_frequency_default(data.pll_d2 > 0).unwrap();
172235
} else {
173236
self.set_cpu_frequency_locked(data.pll_d2 > 0).unwrap();
174237
}
175-
self.do_callbacks()
238+
239+
self.do_callbacks(
240+
cpu_source_before,
241+
cpu_frequency_before,
242+
apb_frequency_before,
243+
self.cpu_source,
244+
self.cpu_frequency,
245+
self.apb_frequency,
246+
);
176247
}
177248
});
178249
}
@@ -202,8 +273,20 @@ impl<'a> super::ClockControl {
202273
(&DFS_MUTEX).lock(|data| {
203274
data.pll_d2 += 1;
204275
if data.pll_d2 == 1 && self.pll_frequency == super::FREQ_OFF {
276+
let cpu_source_before = self.cpu_source;
277+
let cpu_frequency_before = self.cpu_frequency;
278+
let apb_frequency_before = self.apb_frequency;
279+
205280
self.pll_enable(false).unwrap();
206-
self.do_callbacks();
281+
282+
self.do_callbacks(
283+
cpu_source_before,
284+
cpu_frequency_before,
285+
apb_frequency_before,
286+
self.cpu_source,
287+
self.cpu_frequency,
288+
self.apb_frequency,
289+
);
207290
}
208291
});
209292

@@ -216,8 +299,20 @@ impl<'a> super::ClockControl {
216299
data.pll_d2 -= 1;
217300

218301
if data.pll_d2 == 0 && self.cpu_source() != super::CPUSource::PLL {
302+
let cpu_source_before = self.cpu_source;
303+
let cpu_frequency_before = self.cpu_frequency;
304+
let apb_frequency_before = self.apb_frequency;
305+
219306
self.pll_disable();
220-
self.do_callbacks();
307+
308+
self.do_callbacks(
309+
cpu_source_before,
310+
cpu_frequency_before,
311+
apb_frequency_before,
312+
self.cpu_source,
313+
self.cpu_frequency,
314+
self.apb_frequency,
315+
);
221316
}
222317
});
223318
}
@@ -230,7 +325,7 @@ impl<'a> super::ClockControl {
230325
/// TODO: at the moment only static lifetime callbacks are allowed
231326
pub(crate) fn add_callback<F>(&mut self, f: &'static F) -> Result<(), Error>
232327
where
233-
F: Fn(),
328+
F: Fn(super::CPUSource, Hertz, Hertz, super::CPUSource, Hertz, Hertz),
234329
{
235330
// need to disable interrupts, because otherwise deadlock can arise
236331
// when interrupt is called after mutex is obtained and interrupt

src/clock_control/mod.rs

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,12 @@ pub struct ClockControl {
249249
dfs: dfs::DFS,
250250
}
251251

252-
/// Function only available once clock if frozen
253-
pub fn sleep<T: Into<NanoSeconds>>(time: T) {
252+
/// Sleep by spinning
253+
///
254+
/// *Note: Function only available once clock if frozen.embedded_hal*
255+
///
256+
/// *Note: Maximum duration is 2e32-1 ns ~ 4.29s *
257+
pub fn sleep<T: Into<NanoSecondsU64>>(time: T) {
254258
unsafe { CLOCK_CONTROL.as_ref().unwrap().delay(time) };
255259
}
256260

@@ -440,7 +444,7 @@ impl ClockControl {
440444
};
441445

442446
let estimated_time = (Hertz(1_000_000) * (slow_cycles as u32) / slow_freq).us();
443-
let estimated_cycle_count = 2 * self.time_to_cpu_cycles(estimated_time);
447+
let estimated_cycle_count = 2 * (self.time_to_cpu_cycles(estimated_time) as u32);
444448

445449
let max_cycle_count = 0x01FFFFFF; // bit 7:31 = 25 bits
446450
if estimated_cycle_count > max_cycle_count {
@@ -527,6 +531,7 @@ impl ClockControl {
527531
fn init<T: Into<Hertz> + Copy>(&mut self, xtal_frequency: T) -> Result<&mut Self, Error> {
528532
// if auto is selected check if the frequency has already been stored during
529533
// a previous run in the scratch register
534+
530535
if xtal_frequency.into() == XTAL_FREQUENCY_AUTO {
531536
self.xtal_frequency = match self.xtal_frequency_from_scratch() {
532537
Ok(frequency) => frequency,
@@ -585,14 +590,20 @@ impl ClockControl {
585590
}
586591

587592
/// calculate the number of cpu cycles from a time at the current CPU frequency
588-
fn time_to_cpu_cycles<T: Into<NanoSeconds>>(&self, time: T) -> u32 {
589-
(((self.cpu_frequency / Hertz(1_000_000)) as u64) * (u32::from(time.into()) as u64) / 1000)
590-
as u32
593+
fn time_to_cpu_cycles<T: Into<NanoSecondsU64>>(&self, time: T) -> u64 {
594+
((self.cpu_frequency / Hertz(1_000_000)) as u64) * u64::from(time.into()) / 1000
591595
}
592596

593597
/// delay a certain time by spinning
594-
fn delay<T: Into<NanoSeconds>>(&self, time: T) {
595-
delay(self.time_to_cpu_cycles(time));
598+
fn delay<T: Into<NanoSecondsU64>>(&self, time: T) {
599+
let cycles = self.time_to_cpu_cycles(time);
600+
let lower = cycles as u32;
601+
let upper = cycles >> 32;
602+
603+
delay(lower);
604+
for _ in 0..(upper * 2) {
605+
delay(u32::MAX / 2);
606+
}
596607
}
597608

598609
/// Check if a value from RTC_XTAL_FREQ_REG or RTC_APB_FREQ_REG are valid clocks
@@ -626,17 +637,11 @@ impl ClockControl {
626637
T2: Into<Hertz> + Copy + PartialOrd,
627638
T3: Into<Hertz> + Copy + PartialOrd,
628639
{
629-
match cpu_source_default {
630-
CPUSource::APLL => return Err(Error::UnsupportedFreqConfig),
631-
_ => {}
632-
}
633-
match cpu_source_locked {
634-
CPUSource::APLL => return Err(Error::UnsupportedFreqConfig),
635-
_ => {}
636-
}
637-
match cpu_source_apb_locked {
638-
CPUSource::APLL => return Err(Error::UnsupportedFreqConfig),
639-
_ => {}
640+
if cpu_source_default == CPUSource::APLL
641+
|| cpu_source_locked == CPUSource::APLL
642+
|| cpu_source_apb_locked == CPUSource::APLL
643+
{
644+
return Err(Error::UnsupportedFreqConfig);
640645
}
641646

642647
if cpu_frequency_default.into() < CPU_FREQ_MIN
@@ -653,6 +658,12 @@ impl ClockControl {
653658
return Err(Error::FrequencyTooHigh);
654659
}
655660

661+
if cpu_frequency_default.into() > cpu_frequency_apb_locked.into()
662+
|| cpu_frequency_default.into() > cpu_frequency_locked.into()
663+
{
664+
return Err(Error::UnsupportedFreqConfig);
665+
}
666+
656667
self.cpu_source_default = cpu_source_default;
657668
self.cpu_frequency_default =
658669
self.round_cpu_frequency(cpu_source_default, cpu_frequency_default);
@@ -762,6 +773,10 @@ impl ClockControl {
762773
frequency: T,
763774
keep_pll_enabled: bool,
764775
) -> Result<&mut Self, Error> {
776+
if source == self.cpu_source && frequency.into() == self.cpu_frequency {
777+
return Ok(self);
778+
}
779+
765780
match source {
766781
CPUSource::Xtal => self.set_cpu_frequency_to_xtal(frequency)?,
767782
CPUSource::PLL => self.set_cpu_frequency_to_pll(frequency)?,

0 commit comments

Comments
 (0)