-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add clock measurement support, fix VCO min freq & add GPin0/1 clock source support. #683
base: main
Are you sure you want to change the base?
Changes from 5 commits
08504b6
4dbadef
8445d1f
442b662
6cbfae2
fc6a348
8b48e81
3766cde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,7 @@ | |
//! See [Chapter 2 Section 15](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details | ||
use core::{convert::Infallible, marker::PhantomData}; | ||
use fugit::{HertzU32, RateExtU32}; | ||
use pac::clocks::fc0_src::FC0_SRC_A; | ||
|
||
use crate::{ | ||
pac::{self, CLOCKS, PLL_SYS, PLL_USB, RESETS, XOSC}, | ||
|
@@ -79,9 +80,9 @@ use crate::{ | |
mod macros; | ||
mod clock_sources; | ||
|
||
use clock_sources::PllSys; | ||
pub use clock_sources::{GPin0, GPin1}; | ||
|
||
use self::clock_sources::{GPin0, GPin1, PllUsb, Rosc, Xosc}; | ||
use clock_sources::{PllSys, PllUsb, Rosc, Xosc}; | ||
|
||
#[derive(Copy, Clone)] | ||
/// Provides refs to the CLOCKS block. | ||
|
@@ -167,6 +168,9 @@ pub trait StoppableClock: Sealed { | |
|
||
/// Trait for things that can be used as clock source | ||
pub trait ClockSource: Sealed { | ||
/// Associated Frequency counter source. | ||
const FCOUNTER_SRC: FC0_SRC_A; | ||
|
||
/// Get the operating frequency for this source | ||
/// | ||
/// Used to determine the divisor | ||
|
@@ -301,6 +305,46 @@ impl ClocksManager { | |
.configure_clock(&self.system_clock, self.system_clock.freq()) | ||
} | ||
|
||
/// Approximates the frequency of the given clock source. | ||
pub fn approximate_frequency<C: ClockSource>(&mut self, _trg_clk: C) -> HertzU32 { | ||
// Wait for the frequency counter to be ready | ||
while self.clocks.fc0_status.read().running().bit_is_set() { | ||
core::hint::spin_loop() | ||
} | ||
|
||
// Set the speed of the reference clock in kHz. | ||
self.clocks.fc0_ref_khz.write(|w| unsafe { | ||
w.fc0_ref_khz() | ||
.bits(self.reference_clock.get_freq().to_kHz()) | ||
}); | ||
|
||
// Corresponds to a 1ms test time, which seems to give good enough accuracy | ||
ithinuel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.clocks | ||
.fc0_interval | ||
.write(|w| unsafe { w.fc0_interval().bits(10) }); | ||
|
||
// We don't really care about the min/max, so these are just set to min/max values. | ||
self.clocks | ||
.fc0_min_khz | ||
.write(|w| unsafe { w.fc0_min_khz().bits(0) }); | ||
self.clocks | ||
.fc0_max_khz | ||
.write(|w| unsafe { w.fc0_max_khz().bits(0xffffffff) }); | ||
|
||
// To measure rosc directly we use the value 0x03. | ||
ithinuel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.clocks | ||
.fc0_src | ||
.write(|w| w.fc0_src().variant(C::FCOUNTER_SRC)); | ||
|
||
// Wait until the measurement is ready | ||
while self.clocks.fc0_status.read().done().bit_is_clear() { | ||
core::hint::spin_loop() | ||
} | ||
|
||
let speed_hz = self.clocks.fc0_result.read().khz().bits() * 1000; | ||
speed_hz.Hz() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few error bits in FC0_STATUS. This method could check those bits and return an error if any are set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, however it is unclear to me which is set and when.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's some explanation in section 2.15.6.2. Using the frequency counter: "The frequency counter can also be used in a test mode. This allows the hardware to check if the frequency is within In this case, FAST and SLOW don't apply. So the only realistic error case would be DIED. So a simple Or we could define an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strange: I tried to provoke a DIED response:
But I got a successful measurement:
Which isn't exactly wrong - a disabled clock is a 0kHz clock. But then, when does DIED get set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it does when it sees a couple clock cycles and then it stops while measuring is taking place. |
||
} | ||
|
||
/// Releases the CLOCKS block | ||
pub fn free(self) -> CLOCKS { | ||
self.clocks | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,7 +141,7 @@ impl<D: PhaseLockedLoopDevice> PhaseLockedLoop<Disabled, D> { | |
xosc_frequency: HertzU32, | ||
config: PLLConfig, | ||
) -> Result<PhaseLockedLoop<Disabled, D>, Error> { | ||
const VCO_FREQ_RANGE: RangeInclusive<HertzU32> = HertzU32::MHz(400)..=HertzU32::MHz(1_600); | ||
const VCO_FREQ_RANGE: RangeInclusive<HertzU32> = HertzU32::MHz(750)..=HertzU32::MHz(1_600); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we consider this a breaking change and defer it to version 0.10.0? In any case: This will break with the current value of IMHO we should change the value of PLL_USB_48MHZ now (as it's not a breaking change), and change VCO_FREQ_RANGE with version 0.10.0. PLL_USB_48MHZ should become:
(New values taken from https://github.com/raspberrypi/pico-sdk/pull/869/files) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (BTW: This is the error I get when trying to run it without fixing PLL_USB_48MHZ:
) |
||
const POSTDIV_RANGE: Range<u8> = 1..7; | ||
const FBDIV_RANGE: Range<u16> = 16..320; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not obvious if this is safe:
fc0_ref_khz
only has 20 non-reserved bits, so writing a larger value might be undefined.