@@ -158,6 +158,23 @@ impl RtcConfig {
158
158
}
159
159
}
160
160
161
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
162
+ #[ repr( u8 ) ]
163
+ pub enum RtcCalibrationCyclePeriod {
164
+ /// 8-second calibration period
165
+ Seconds8 ,
166
+ /// 16-second calibration period
167
+ Seconds16 ,
168
+ /// 32-second calibration period
169
+ Seconds32 ,
170
+ }
171
+
172
+ impl Default for RtcCalibrationCyclePeriod {
173
+ fn default ( ) -> Self {
174
+ RtcCalibrationCyclePeriod :: Seconds32
175
+ }
176
+ }
177
+
161
178
impl Rtc {
162
179
pub fn rtc (
163
180
rtc : RTC ,
@@ -479,6 +496,71 @@ impl Rtc {
479
496
self . rtc_config = rtc_config;
480
497
}
481
498
499
+ const RTC_CALR_MIN_PPM : f32 = -487.1 ;
500
+ const RTC_CALR_MAX_PPM : f32 = 488.5 ;
501
+ const RTC_CALR_RESOLUTION_PPM : f32 = 0.9537 ;
502
+
503
+ /// Calibrate the clock drift.
504
+ ///
505
+ /// `clock_drift` can be adjusted from -487.1 ppm to 488.5 ppm and is clamped to this range.
506
+ ///
507
+ /// ### Note
508
+ ///
509
+ /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
510
+ /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
511
+ pub fn calibrate ( & mut self , mut clock_drift : f32 , period : RtcCalibrationCyclePeriod ) {
512
+ if clock_drift < Self :: RTC_CALR_MIN_PPM {
513
+ clock_drift = Self :: RTC_CALR_MIN_PPM ;
514
+ } else if clock_drift > Self :: RTC_CALR_MAX_PPM {
515
+ clock_drift = Self :: RTC_CALR_MAX_PPM ;
516
+ }
517
+
518
+ clock_drift = clock_drift / Self :: RTC_CALR_RESOLUTION_PPM ;
519
+
520
+ self . write ( false , |rtc| {
521
+ rtc. calr . modify ( |_, w| unsafe {
522
+ match period {
523
+ RtcCalibrationCyclePeriod :: Seconds8 => {
524
+ w. calw8 ( ) . set_bit ( ) . calw16 ( ) . clear_bit ( ) ;
525
+ }
526
+ RtcCalibrationCyclePeriod :: Seconds16 => {
527
+ w. calw8 ( ) . clear_bit ( ) . calw16 ( ) . set_bit ( ) ;
528
+ }
529
+ RtcCalibrationCyclePeriod :: Seconds32 => {
530
+ w. calw8 ( ) . clear_bit ( ) . calw16 ( ) . clear_bit ( ) ;
531
+ }
532
+ }
533
+
534
+ // Extra pulses during calibration cycle period: CALP * 512 - CALM
535
+ //
536
+ // CALP sets whether pulses are added or omitted.
537
+ //
538
+ // CALM contains how many pulses (out of 512) are masked in a
539
+ // given calibration cycle period.
540
+ if clock_drift > 0.0 {
541
+ // Maximum (about 512.2) rounds to 512.
542
+ clock_drift += 0.5 ;
543
+
544
+ // When the offset is positive (0 to 512), the opposite of
545
+ // the offset (512 - offset) is masked, i.e. for the
546
+ // maximum offset (512), 0 pulses are masked.
547
+ w. calp ( ) . set_bit ( ) . calm ( ) . bits ( 512 - clock_drift as u16 )
548
+ } else {
549
+ // Minimum (about -510.7) rounds to -511.
550
+ clock_drift -= 0.5 ;
551
+
552
+ // When the offset is negative or zero (-511 to 0),
553
+ // the absolute offset is masked, i.e. for the minimum
554
+ // offset (-511), 511 pulses are masked.
555
+ w. calp ( )
556
+ . clear_bit ( )
557
+ . calm ( )
558
+ . bits ( ( clock_drift * -1.0 ) as u16 )
559
+ }
560
+ } ) ;
561
+ } )
562
+ }
563
+
482
564
/// Access the wakeup timer
483
565
pub fn wakeup_timer ( & mut self ) -> WakeupTimer {
484
566
WakeupTimer { rtc : self }
0 commit comments