@@ -158,6 +158,23 @@ impl RtcConfig {
158158 }
159159}
160160
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+
161178impl Rtc {
162179 pub fn rtc (
163180 rtc : RTC ,
@@ -479,6 +496,71 @@ impl Rtc {
479496 self . rtc_config = rtc_config;
480497 }
481498
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+
482564 /// Access the wakeup timer
483565 pub fn wakeup_timer ( & mut self ) -> WakeupTimer {
484566 WakeupTimer { rtc : self }
0 commit comments