@@ -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,12 @@ 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 > (
334
+ & mut self ,
335
+ _trg_clk : C ,
336
+ accuracy : FCAccuracy ,
337
+ ) -> HertzU32 {
310
338
// Wait for the frequency counter to be ready
311
339
while self . clocks . fc0_status . read ( ) . running ( ) . bit_is_set ( ) {
312
340
core:: hint:: spin_loop ( )
@@ -318,10 +346,14 @@ impl ClocksManager {
318
346
. bits ( self . reference_clock . get_freq ( ) . to_kHz ( ) )
319
347
} ) ;
320
348
321
- // Corresponds to a 1ms test time, which seems to give good enough accuracy
349
+ // > The test interval is 0.98us * 2**interval, but let's call it 1us * 2**interval.
350
+ // > The default gives a test interval of 250us
351
+ //
352
+ // https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#reg-clocks-FC0_INTERVAL
353
+ // https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#table-fc-test-interval
322
354
self . clocks
323
355
. fc0_interval
324
- . write ( |w| unsafe { w. fc0_interval ( ) . bits ( 10 ) } ) ;
356
+ . write ( |w| unsafe { w. fc0_interval ( ) . bits ( accuracy as u8 ) } ) ;
325
357
326
358
// We don't really care about the min/max, so these are just set to min/max values.
327
359
self . clocks
@@ -331,7 +363,7 @@ impl ClocksManager {
331
363
. fc0_max_khz
332
364
. write ( |w| unsafe { w. fc0_max_khz ( ) . bits ( 0xffffffff ) } ) ;
333
365
334
- // To measure rosc directly we use the value 0x03 .
366
+ // Select which clock to measure .
335
367
self . clocks
336
368
. fc0_src
337
369
. write ( |w| w. fc0_src ( ) . variant ( C :: FCOUNTER_SRC ) ) ;
@@ -341,7 +373,10 @@ impl ClocksManager {
341
373
core:: hint:: spin_loop ( )
342
374
}
343
375
344
- let speed_hz = self . clocks . fc0_result . read ( ) . khz ( ) . bits ( ) * 1000 ;
376
+ // TODO: the result may not be valid (eg clock stopped during measurement). We may want to
377
+ // return a Result instead. Is it worth the hassle though?
378
+ let result = self . clocks . fc0_result . read ( ) ;
379
+ let speed_hz = result. khz ( ) . bits ( ) * 1000 + result. frac ( ) . bits ( ) ;
345
380
speed_hz. Hz ( )
346
381
}
347
382
0 commit comments