@@ -84,6 +84,30 @@ pub use clock_sources::{GPin0, GPin1};
84
84
85
85
use clock_sources:: { PllSys , PllUsb , Rosc , Xosc } ;
86
86
87
+ /// Frequency counter accuracy
88
+ ///
89
+ /// See: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#table-fc-test-interval
90
+ #[ repr( u8 ) ]
91
+ #[ allow( missing_docs) ]
92
+ pub enum FCAccuracy {
93
+ _2048kHz = 0 ,
94
+ _1024kHz,
95
+ _512kHz,
96
+ _256kHz,
97
+ _128kHz,
98
+ _64kHz,
99
+ _32kHz,
100
+ _16kHz,
101
+ _8kHz,
102
+ _4kHz,
103
+ _2kHz,
104
+ _1kHz,
105
+ _500Hz,
106
+ _250Hz,
107
+ _125Hz,
108
+ _62_5Hz,
109
+ }
110
+
87
111
#[ derive( Copy , Clone ) ]
88
112
/// Provides refs to the CLOCKS block.
89
113
struct ShareableClocks {
@@ -305,8 +329,8 @@ impl ClocksManager {
305
329
. configure_clock ( & self . system_clock , self . system_clock . freq ( ) )
306
330
}
307
331
308
- /// Approximates the frequency of the given clock source.
309
- pub fn approximate_frequency < C : ClockSource > ( & mut self , _trg_clk : C ) -> HertzU32 {
332
+ /// Measure the frequency of the given clock source by approximation .
333
+ pub fn measure_frequency < C : ClockSource > ( & mut self , _trg_clk : C , accuracy : FCAccuracy ) -> HertzU32 {
310
334
// Wait for the frequency counter to be ready
311
335
while self . clocks . fc0_status . read ( ) . running ( ) . bit_is_set ( ) {
312
336
core:: hint:: spin_loop ( )
@@ -318,10 +342,14 @@ impl ClocksManager {
318
342
. bits ( self . reference_clock . get_freq ( ) . to_kHz ( ) )
319
343
} ) ;
320
344
321
- // Corresponds to a 1ms test time, which seems to give good enough accuracy
345
+ // > The test interval is 0.98us * 2**interval, but let's call it 1us * 2**interval.
346
+ // > The default gives a test interval of 250us
347
+ //
348
+ // https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#reg-clocks-FC0_INTERVAL
349
+ // https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#table-fc-test-interval
322
350
self . clocks
323
351
. fc0_interval
324
- . write ( |w| unsafe { w. fc0_interval ( ) . bits ( 10 ) } ) ;
352
+ . write ( |w| unsafe { w. fc0_interval ( ) . bits ( accuracy as u8 ) } ) ;
325
353
326
354
// We don't really care about the min/max, so these are just set to min/max values.
327
355
self . clocks
@@ -331,7 +359,7 @@ impl ClocksManager {
331
359
. fc0_max_khz
332
360
. write ( |w| unsafe { w. fc0_max_khz ( ) . bits ( 0xffffffff ) } ) ;
333
361
334
- // To measure rosc directly we use the value 0x03 .
362
+ // Select which clock to measure .
335
363
self . clocks
336
364
. fc0_src
337
365
. write ( |w| w. fc0_src ( ) . variant ( C :: FCOUNTER_SRC ) ) ;
@@ -341,6 +369,8 @@ impl ClocksManager {
341
369
core:: hint:: spin_loop ( )
342
370
}
343
371
372
+ // TODO: the result may not be valid (eg clock stopped during measurement). We may want to
373
+ // return a Result instead. Is it worth the hassle though?
344
374
let speed_hz = self . clocks . fc0_result . read ( ) . khz ( ) . bits ( ) * 1000 ;
345
375
speed_hz. Hz ( )
346
376
}
0 commit comments