@@ -7,9 +7,18 @@ use crate::backup_domain::BackupDomain;
77use crate :: time:: Hertz ;
88
99use core:: convert:: Infallible ;
10+ use core:: marker:: PhantomData ;
1011
1112// The LSE runs at at 32 768 hertz unless an external clock is provided
1213const LSE_HERTZ : u32 = 32_768 ;
14+ const LSI_HERTZ : u32 = 40_000 ;
15+
16+ /// RTC clock source HSE clock divided by 128 (type state)
17+ pub struct RtcClkHseDiv128 ;
18+ /// RTC clock source LSE oscillator clock (type state)
19+ pub struct RtcClkLse ;
20+ /// RTC clock source LSI oscillator clock (type state)
21+ pub struct RtcClkLsi ;
1322
1423/**
1524 Real time clock
@@ -28,11 +37,12 @@ const LSE_HERTZ: u32 = 32_768;
2837 [examples/blinky_rtc.rs]: https://github.com/stm32-rs/stm32f1xx-hal/blob/v0.7.0/examples/blinky_rtc.rs
2938*/
3039
31- pub struct Rtc {
40+ pub struct Rtc < CS = RtcClkLse > {
3241 regs : RTC ,
42+ _clock_source : PhantomData < CS > ,
3343}
3444
35- impl Rtc {
45+ impl Rtc < RtcClkLse > {
3646 /**
3747 Initialises the RTC. The `BackupDomain` struct is created by
3848 `Rcc.bkp.constrain()`.
@@ -43,10 +53,13 @@ impl Rtc {
4353 power cycles where (VBAT) still has power. Use [set_time](#method.set_time) if you want to
4454 reset the counter.
4555 */
46- pub fn rtc ( regs : RTC , bkp : & mut BackupDomain ) -> Self {
47- let mut result = Rtc { regs } ;
56+ pub fn new ( regs : RTC , bkp : & mut BackupDomain ) -> Self {
57+ let mut result = Rtc {
58+ regs,
59+ _clock_source : PhantomData ,
60+ } ;
4861
49- Rtc :: enable_rtc ( bkp) ;
62+ Self :: enable_rtc ( bkp) ;
5063
5164 // Set the prescaler to make it count up once every second.
5265 let prl = LSE_HERTZ - 1 ;
@@ -77,7 +90,95 @@ impl Rtc {
7790 . lse ( )
7891 } )
7992 }
93+ }
94+
95+ impl Rtc < RtcClkLsi > {
96+ pub fn rtc ( regs : RTC , bkp : & mut BackupDomain ) -> Self {
97+ let mut result = Rtc {
98+ regs,
99+ _clock_source : PhantomData ,
100+ } ;
101+
102+ Self :: enable_rtc ( bkp) ;
103+
104+ // Set the prescaler to make it count up once every second.
105+ let prl = LSI_HERTZ - 1 ;
106+ assert ! ( prl < 1 << 20 ) ;
107+ result. perform_write ( |s| {
108+ s. regs . prlh . write ( |w| unsafe { w. bits ( prl >> 16 ) } ) ;
109+ s. regs . prll . write ( |w| unsafe { w. bits ( prl as u16 as u32 ) } ) ;
110+ } ) ;
111+
112+ result
113+ }
114+
115+ /// Enables the RTC device with the lsi as the clock
116+ fn enable_rtc ( _bkp : & mut BackupDomain ) {
117+ // NOTE: Safe RCC access because we are only accessing bdcr
118+ // and we have a &mut on BackupDomain
119+ let rcc = unsafe { & * RCC :: ptr ( ) } ;
120+ rcc. csr . modify ( |_, w| {
121+ w
122+ // start the LSI oscillator
123+ . lsion ( )
124+ . set_bit ( )
125+ } ) ;
126+ rcc. bdcr . modify ( |_, w| {
127+ w
128+ // Enable the RTC
129+ . rtcen ( )
130+ . set_bit ( )
131+ // Set the source of the RTC to LSI
132+ . rtcsel ( )
133+ . lsi ( )
134+ } )
135+ }
136+ }
137+
138+ impl Rtc < RtcClkHseDiv128 > {
139+ pub fn rtc < F > ( regs : RTC , bkp : & mut BackupDomain , hse : F ) -> Self
140+ where
141+ F : Into < Hertz > ,
142+ {
143+ let mut result = Rtc {
144+ regs,
145+ _clock_source : PhantomData ,
146+ } ;
147+
148+ Self :: enable_rtc ( bkp) ;
149+
150+ // Set the prescaler to make it count up once every second.
151+ let prl = hse. into ( ) . 0 / 128 - 1 ;
152+ assert ! ( prl < 1 << 20 ) ;
153+ result. perform_write ( |s| {
154+ s. regs . prlh . write ( |w| unsafe { w. bits ( prl >> 16 ) } ) ;
155+ s. regs . prll . write ( |w| unsafe { w. bits ( prl as u16 as u32 ) } ) ;
156+ } ) ;
157+
158+ result
159+ }
160+
161+ /// Enables the RTC device with the lsi as the clock
162+ fn enable_rtc ( _bkp : & mut BackupDomain ) {
163+ // NOTE: Safe RCC access because we are only accessing bdcr
164+ // and we have a &mut on BackupDomain
165+ let rcc = unsafe { & * RCC :: ptr ( ) } ;
166+ if rcc. cr . read ( ) . hserdy ( ) . bit_is_clear ( ) {
167+ panic ! ( "HSE oscillator not ready" ) ;
168+ }
169+ rcc. bdcr . modify ( |_, w| {
170+ w
171+ // Enable the RTC
172+ . rtcen ( )
173+ . set_bit ( )
174+ // Set the source of the RTC to HSE/128
175+ . rtcsel ( )
176+ . hse ( )
177+ } )
178+ }
179+ }
80180
181+ impl < CS > Rtc < CS > {
81182 /// Selects the frequency of the RTC Timer
82183 /// NOTE: Maximum frequency of 16384 Hz using the internal LSE
83184 pub fn select_frequency ( & mut self , timeout : impl Into < Hertz > ) {
0 commit comments