mcp795xx/
lib.rs

1//#![deny(missing_docs)]
2//#![deny(warnings)]
3#![no_std]
4#![allow(non_snake_case)]
5
6extern crate embedded_hal as hal;
7use hal::blocking::spi;
8use hal::digital::v2::OutputPin;
9
10mod registers;
11pub mod datetime;
12
13pub use datetime::DateTime;
14
15//#[macro_use]
16extern crate bitfield;
17
18
19/// MCP795xx Driver
20pub struct Mcp795xx<SPI, CS> {
21    spi: SPI,
22    cs: CS,
23}
24
25
26impl<SPI, CS, E1, E2> Mcp795xx<SPI, CS>
27    where SPI: spi::Transfer<u8, Error = E1> + spi::Write<u8, Error = E1>,
28          CS:  OutputPin<Error = E2>,
29          E1: core::fmt::Debug,
30          E2: core::fmt::Debug
31{
32    pub fn new(spi: SPI, cs: CS) -> Self {
33        Self {
34            spi: spi,
35            cs: cs
36        }
37    }
38
39    pub fn enable_oscillator(&mut self) {
40        let mut buff = [0 as u8; 3];
41
42        buff[0] = Instructions::READ as u8;
43        buff[1] = Addresses::RTCSEC as u8;
44
45        self.cs.set_low().unwrap();
46        self.spi.transfer(&mut buff).unwrap();
47        self.cs.set_high().unwrap();
48
49        let osc_enabled = registers::RTCSEC(buff[2]).ST();
50
51        if !osc_enabled {
52            buff[0] = Instructions::WRITE as u8;
53            buff[1] = Addresses::RTCSEC as u8;
54            let mut seconds = registers::RTCSEC(0);
55            seconds.set_st(true);
56            buff[2] = seconds.0;
57            self.cs.set_low().unwrap();
58            self.spi.transfer(&mut buff).unwrap();
59            self.cs.set_high().unwrap();
60        }
61    }
62
63    pub fn enable_vbat(&mut self) {
64        let mut buff = [0 as u8; 3];
65
66        buff[0] = Instructions::READ as u8;
67        buff[1] = Addresses::RTCWKDAY as u8;
68
69        self.cs.set_low().unwrap();
70        self.spi.transfer(&mut buff).unwrap();
71        self.cs.set_high().unwrap();
72
73        let vbat_enabled = registers::RTCWKDAY(buff[2]).VBATEN();
74
75        if !vbat_enabled {
76            buff[0] = Instructions::WRITE as u8;
77            buff[1] = Addresses::RTCWKDAY as u8;
78            let mut reg = registers::RTCWKDAY(0);
79            reg.set_VBATEN(true);
80            buff[2] = reg.0;
81            self.cs.set_low().unwrap();
82            self.spi.transfer(&mut buff).unwrap();
83            self.cs.set_high().unwrap();
84        }
85    }
86    pub fn get_time(&mut self) -> DateTime {
87        let mut buff = [0 as u8; 10];
88
89        // Instruction
90        buff[0] = Instructions::READ as u8;
91
92        // Address
93        buff[1] = Addresses::RTCSEC as u8;
94
95        self.cs.set_low().unwrap();
96        self.spi.transfer(&mut buff).unwrap();
97        self.cs.set_high().unwrap();
98
99        DateTime {
100            seconds : registers::RTCSEC(buff[2]).seconds(),
101            minutes : registers::RTCMIN(buff[3]).minutes(),
102            hours : registers::RTCHOUR(buff[4]).hours(),
103            weekday : registers::RTCWKDAY(buff[5]).WKDAY(),
104            date : registers::RTCDATE(buff[6]).date(),
105            month : registers::RTCMTH(buff[7]).month(),
106            year : registers::RTCYEAR(buff[8]).year()
107        }
108    }
109
110    pub fn set_time(&mut self, datetime: DateTime) {
111
112        let mut seconds = registers::RTCSEC(0);
113        seconds.set_seconds(datetime.seconds);
114        seconds.set_st(true);
115
116        let mut minutes = registers::RTCMIN(0);
117        minutes.set_minutes(datetime.minutes);
118
119        let mut hours = registers::RTCHOUR(0);
120        hours.set_hours_military(datetime.hours);
121
122        let mut weekday = registers::RTCWKDAY(0);
123        weekday.set_PWRFAIL(false);
124        weekday.set_VBATEN(true);
125        weekday.set_WKDAY(datetime.weekday);
126
127        let mut date = registers::RTCDATE(0);
128        date.set_date(datetime.date);
129
130        let mut month = registers::RTCMTH(0);
131        month.set_month(datetime.month);
132
133        let mut year = registers::RTCYEAR(0);
134        year.set_year(datetime.year);
135
136        let buff = [
137            // Instruction
138            (Instructions::WRITE as u8),
139            // Address
140            Addresses::RTCHSEC as u8,
141            0, // set hundreths of seconds to 0
142            seconds.0,
143            minutes.0,
144            hours.0,
145            weekday.0,
146            date.0,
147            month.0,
148            year.0,
149        ];
150
151        self.cs.set_low().unwrap();
152        self.spi.write(&buff).unwrap();
153        self.cs.set_high().unwrap();
154    }
155}
156
157#[allow(unused)]
158enum Instructions {
159    /// Read data from EEPROM array beginning at selected address
160    EEREAD = 0b0000_0011,
161    /// Write data to EEPROM array beginning at selected address
162    EEWRITE = 0b0000_0010,
163    /// Reset the write enable latch (disable write operations)
164    EEWRDI = 0b0000_0100,
165    /// Set the write enable latch (enable write operations)
166    EEWREN = 0b0000_0110,
167    /// Read STATUS register
168    SRREAD = 0b0000_0101,
169    /// Write STATUS register
170    SRWRITE = 0b0000_0001,
171    /// Read data from RTCC/SRAM array beginning at selected address
172    READ = 0b0001_0011,
173    /// Write data to RTCC/SRAM array beginning at selected address
174    WRITE = 0b0001_0010,
175    /// Unlock the protected EEPROM block for a write operation
176    UNLOCK = 0b0001_0100,
177    /// Write data to the protected EEPROM block beginning at selected address
178    IDWRITE = 0b0011_0010,
179    /// Read data from the protected EEPROM block beginning at the selected address
180    IDREAD = 0b0011_0011,
181    /// Clear all SRAM data to 0
182    CLRRAM = 0b0101_0100,
183}
184
185#[allow(unused)]
186enum Addresses {
187    RTCHSEC = 0x00,
188    RTCSEC= 0x01,
189    RTCMIN = 0x02,
190    RTCHOUR= 0x03,
191    RTCWKDAY= 0x04,
192    RTCDATE= 0x05,
193    RTCMTH= 0x06,
194    RTCYEAR= 0x07,
195    CONTROL= 0x08,
196    ALM0SEC= 0x0C,
197    ALM0MIN= 0x0D,
198    ALM0HOUR= 0x0E,
199    ALM0WKDAY= 0x0F,
200    ALM0DATE= 0x10,
201    ALM0MTH= 0x11,
202    ALM1HSEC= 0x12,
203    ALM1SEC= 0x13,
204    ALM1MIN= 0x14,
205    ALM1HOUR= 0x15,
206    ALM1WKDAY= 0x16,
207    ALM1DATE= 0x17,
208    PWRDNMIN= 0x18,
209    PWRDNHOUR= 0x19,
210    PWRDNDATE= 0x1A,
211    PWRDNMTH= 0x1B,
212    PWRUPMIN= 0x1C,
213    PWRUPHOUR= 0x1D,
214    PWRUPDATE= 0x1E,
215    PWRUPMTH= 0x1F,
216}
217
218
219#[cfg(test)]
220#[macro_use]
221extern crate std;
222mod tests {
223    // Note this useful idiom: importing names from outer (for mod tests) scope.
224
225}