stm32l4_hal/
rtc.rs

1//! RTC peripheral abstraction
2
3use crate::datetime::*;
4use crate::rcc::{BDCR, APB1R1};
5use crate::pwr;
6use crate::stm32::{RTC};
7
8/// RTC Abstraction
9pub struct Rtc {
10    rtc: RTC
11}
12
13impl Rtc {
14    pub fn rtc(rtc: RTC, apb1r1: &mut APB1R1, bdcr: &mut BDCR, pwrcr1: &mut pwr::CR1) -> Self {
15        // enable peripheral clock for communication
16        apb1r1.enr().modify(|_, w| w.rtcapben().set_bit());
17        pwrcr1.reg().read(); // read to allow the pwr clock to enable
18        
19        pwrcr1.reg().modify(|_, w| w.dbp().set_bit());
20        while pwrcr1.reg().read().dbp().bit_is_clear() {}
21        
22        bdcr.enr().modify(|_, w| { w.bdrst().set_bit() }); // reset
23        
24        bdcr.enr().modify(|_, w| unsafe {
25            w.rtcsel()
26                /* 
27                    00: No clock
28                    01: LSE oscillator clock used as RTC clock
29                    10: LSI oscillator clock used as RTC clock
30                    11: HSE oscillator clock divided by 32 used as RTC clock 
31                */
32                .bits(0b10)
33                .rtcen()
34                .set_bit()
35                .bdrst() // reset required for clock source change
36                .clear_bit()
37        });
38
39
40       write_protection(&rtc, false);
41        {
42            init_mode(&rtc, true);
43            {
44                rtc.cr.modify(|_, w| unsafe {
45                    w.fmt()
46                        .clear_bit() // 24hr
47                        .osel()
48                        /* 
49                            00: Output disabled
50                            01: Alarm A output enabled
51                            10: Alarm B output enabled
52                            11: Wakeup output enabled 
53                        */
54                        .bits(0b00)
55                        .pol()
56                        .clear_bit() // pol high
57                });
58                
59                rtc.prer.modify(|_, w| unsafe {
60                    w.prediv_s()
61                        .bits(255)
62                        .prediv_a()
63                        .bits(127)
64                });
65            }
66            init_mode(&rtc, false);
67
68            // TODO configuration for output pins
69            rtc.or.modify(|_, w| {
70                w.rtc_alarm_type()
71                    .clear_bit()
72                    .rtc_out_rmp()
73                    .clear_bit()
74            });
75            
76        }
77        write_protection(&rtc, true);
78
79        Self {
80            rtc: rtc
81        }
82    }
83
84    pub fn set_time(&self, time: &Time){
85        write_protection(&self.rtc, false);
86        {
87            init_mode(&self.rtc, true);
88            {
89                
90                let (ht, hu) = byte_to_bcd2(time.hours as u8);
91                let (mnt, mnu) = byte_to_bcd2(time.minutes as u8);
92                let (st, su) = byte_to_bcd2(time.seconds as u8);
93                self.rtc.tr.write(|w| unsafe {
94                    w.ht().bits(ht)
95                        .hu().bits(hu)
96                        .mnt().bits(mnt)
97                        .mnu().bits(mnu)
98                        .st().bits(st)
99                        .su().bits(su)
100                        .pm()
101                        .clear_bit()
102
103                });
104
105                self.rtc.cr.modify(|_, w| {
106                    w.fmt()
107                        .bit(time.daylight_savings)
108
109                });
110            }
111            init_mode(&self.rtc, false);
112        }
113        write_protection(&self.rtc, true);
114    }
115
116    pub fn get_time(&self) -> Time {
117        let time;
118        
119        let timer = self.rtc.tr.read();
120        let cr = self.rtc.cr.read();
121        time = Time::new(bcd2_to_byte((timer.ht().bits(), timer.hu().bits())).into(), 
122                        bcd2_to_byte((timer.mnt().bits(), timer.mnu().bits())).into(),
123                        bcd2_to_byte((timer.st().bits(), timer.su().bits())).into(),
124                        cr.fmt().bit());
125        
126        write_protection(&self.rtc, true);
127        
128        time
129    }
130
131    pub fn set_date(&self, date: &Date){
132        write_protection(&self.rtc, false);
133        {
134            init_mode(&self.rtc, true);
135            {
136                let (dt, du) = byte_to_bcd2(date.date as u8);
137                let (mt, mu) = byte_to_bcd2(date.month as u8);
138                let yr = date.year as u16;
139                let yr_offset = (yr - 1970_u16) as u8;
140                let (yt, yu) = byte_to_bcd2(yr_offset);
141
142                self.rtc.dr.write(|w| unsafe {
143                    w.dt().bits(dt)
144                        .du().bits(du)
145                        .mt().bit(mt > 0)
146                        .mu().bits(mu)
147                        .yt().bits(yt)
148                        .yu().bits(yu)
149                        .wdu().bits(date.day as u8)
150                });
151
152
153            }
154            init_mode(&self.rtc, false);
155        }
156        write_protection(&self.rtc, true);
157    }
158
159    pub fn get_date(&self) -> Date {
160        let date;
161        
162        let dater = self.rtc.dr.read();
163        date = Date::new(dater.wdu().bits().into(), 
164                        bcd2_to_byte((dater.dt().bits(), dater.du().bits())).into(),
165                        bcd2_to_byte((dater.mt().bit() as u8, dater.mu().bits())).into(),
166                        (bcd2_to_byte((dater.yt().bits(), dater.yu().bits())) as u16 + 1970_u16).into());
167        date
168    }
169    
170}
171
172fn write_protection(rtc: &RTC, enable: bool){
173    if enable {
174        rtc.wpr.write(|w| unsafe {
175            w.bits(0xFF)
176        });
177    } else {
178        rtc.wpr.write(|w| unsafe {
179            w.bits(0xCA)
180        });
181
182        rtc.wpr.write(|w| unsafe {
183            w.bits(0x53)
184        });
185    }
186}
187
188fn init_mode(rtc: &RTC, enabled: bool) {
189    if enabled {
190        let isr = rtc.isr.read();
191        if isr.initf().bit_is_clear() { // are we already in init mode?
192            rtc.isr.write(|w| { w.init().set_bit() });
193            // rtc.isr.write(|w| unsafe { w.bits(0xFFFFFFFF) }); // Sets init mode
194            while rtc.isr.read().initf().bit_is_clear() {} // wait to return to init state
195        } 
196    } else {
197        rtc.isr.write(|w| { w.init().clear_bit() }); // Exits init mode
198    }
199    
200}
201
202fn byte_to_bcd2(byte: u8) -> (u8, u8){
203    let mut bcd_high: u8 = 0;
204    let mut value = byte;
205    
206    while value >= 10 {
207        bcd_high += 1;
208        value -= 10;
209    }
210
211    (bcd_high, ((bcd_high << 4) | value) as u8)
212}
213
214fn bcd2_to_byte(bcd: (u8, u8)) -> u8 { // TODO fix this
215    let value = bcd.1 | bcd.0 << 4;
216    
217    let tmp = ((value & 0xF0) >> 0x4) * 10;
218    
219    (tmp + (value & 0x0F))
220}