stm32_rust_template/bsp/
ds1307.rs

1use crate::driver::i2c::{I2c, Result};
2
3/// DS1307 RTC chip I2C address
4const DS1307_I2C_ADDRESS: u32 = 0x68;
5
6/// DS1307 Register addresses
7const DS1307_ADDR_SEC: u8 = 0x00;
8const DS1307_ADDR_MIN: u8 = 0x01;
9const DS1307_ADDR_HRS: u8 = 0x02;
10const DS1307_ADDR_DAY: u8 = 0x03;
11const DS1307_ADDR_DATE: u8 = 0x04;
12const DS1307_ADDR_MONTH: u8 = 0x05;
13const DS1307_ADDR_YEAR: u8 = 0x06;
14
15/// Time format constants
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum TimeFormat {
18    /// 12-hour format AM
19    TwelveHoursAM = 0,
20    /// 12-hour format PM
21    TwelveHoursPM = 1,
22    /// 24-hour format
23    TwentyFourHours = 2,
24}
25
26/// Days of the week
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum DayOfWeek {
29    Sunday = 1,
30    Monday = 2,
31    Tuesday = 3,
32    Wednesday = 4,
33    Thursday = 5,
34    Friday = 6,
35    Saturday = 7,
36}
37
38/// RTC Date structure
39#[derive(Debug, Clone, Copy)]
40pub struct RtcDate {
41    pub date: u8,
42    pub month: u8,
43    pub year: u8,
44    pub day: DayOfWeek,
45}
46
47/// RTC Time structure
48#[derive(Debug, Clone, Copy)]
49pub struct RtcTime {
50    pub seconds: u8,
51    pub minutes: u8,
52    pub hours: u8,
53    pub time_format: TimeFormat,
54}
55
56/// DS1307 RTC Driver
57pub struct DS1307<I2C> {
58    i2c: I2C,
59}
60
61impl<I2C> DS1307<I2C>
62where
63    I2C: I2c<'static>,
64{
65    /// Create a new DS1307 driver instance
66    pub fn new(i2c: I2C) -> Self {
67        Self { i2c }
68    }
69
70    /// Initialize the DS1307 RTC
71    /// Returns Ok(()) if initialization successful, Err if clock halt bit is set
72    pub fn init(&mut self) -> Result<()> {
73        // Clear the clock halt bit (bit 7 of seconds register)
74        self.write_register(DS1307_ADDR_SEC, 0x00)?;
75
76        // Read back the clock halt bit to verify initialization
77        let clock_state = self.read_register(DS1307_ADDR_SEC)?;
78
79        // Check if clock halt bit (bit 7) is still set
80        if (clock_state >> 7) & 0x1 != 0 {
81            return Err(-1); // Initialization failed
82        }
83
84        Ok(())
85    }
86
87    /// Set the current time on the DS1307
88    pub fn set_current_time(&mut self, rtc_time: &RtcTime) -> Result<()> {
89        // Convert seconds to BCD and clear clock halt bit
90        let mut seconds = Self::binary_to_bcd(rtc_time.seconds);
91        seconds &= !(1 << 7); // Clear bit 7 (clock halt)
92        self.write_register(DS1307_ADDR_SEC, seconds)?;
93
94        // Convert and write minutes
95        let minutes = Self::binary_to_bcd(rtc_time.minutes);
96        self.write_register(DS1307_ADDR_MIN, minutes)?;
97
98        // Handle hours with time format
99        let mut hours = Self::binary_to_bcd(rtc_time.hours);
100        match rtc_time.time_format {
101            TimeFormat::TwentyFourHours => {
102                hours &= !(1 << 6); // Clear 12/24 hour bit for 24-hour format
103            }
104            TimeFormat::TwelveHoursAM => {
105                hours |= 1 << 6; // Set 12/24 hour bit for 12-hour format
106                hours &= !(1 << 5); // Clear AM/PM bit for AM
107            }
108            TimeFormat::TwelveHoursPM => {
109                hours |= 1 << 6; // Set 12/24 hour bit for 12-hour format
110                hours |= 1 << 5; // Set AM/PM bit for PM
111            }
112        }
113        self.write_register(DS1307_ADDR_HRS, hours)?;
114
115        Ok(())
116    }
117
118    /// Set the current date on the DS1307
119    pub fn set_current_date(&mut self, rtc_date: &RtcDate) -> Result<()> {
120        self.write_register(DS1307_ADDR_DATE, Self::binary_to_bcd(rtc_date.date))?;
121        self.write_register(DS1307_ADDR_MONTH, Self::binary_to_bcd(rtc_date.month))?;
122        self.write_register(DS1307_ADDR_YEAR, Self::binary_to_bcd(rtc_date.year))?;
123        self.write_register(DS1307_ADDR_DAY, Self::binary_to_bcd(rtc_date.day as u8))?;
124        Ok(())
125    }
126
127    /// Get the current time from the DS1307
128    pub fn get_current_time(&mut self) -> Result<RtcTime> {
129        // Read seconds and clear clock halt bit
130        let mut seconds = self.read_register(DS1307_ADDR_SEC)?;
131        seconds &= !(1 << 7); // Clear clock halt bit for BCD conversion
132
133        let minutes = self.read_register(DS1307_ADDR_MIN)?;
134        let mut hours = self.read_register(DS1307_ADDR_HRS)?;
135
136        // Determine time format and extract hours
137        let time_format = if (hours & (1 << 6)) != 0 {
138            // 12-hour format
139            let is_pm = (hours & (1 << 5)) != 0;
140            hours &= !(0x3 << 5); // Clear bits 6 and 5
141            if is_pm {
142                TimeFormat::TwelveHoursPM
143            } else {
144                TimeFormat::TwelveHoursAM
145            }
146        } else {
147            // 24-hour format
148            TimeFormat::TwentyFourHours
149        };
150
151        Ok(RtcTime {
152            seconds: Self::bcd_to_binary(seconds),
153            minutes: Self::bcd_to_binary(minutes),
154            hours: Self::bcd_to_binary(hours),
155            time_format,
156        })
157    }
158
159    /// Get the current date from the DS1307
160    pub fn get_current_date(&mut self) -> Result<RtcDate> {
161        let day_raw = self.read_register(DS1307_ADDR_DAY)?;
162        let date = self.read_register(DS1307_ADDR_DATE)?;
163        let month = self.read_register(DS1307_ADDR_MONTH)?;
164        let year = self.read_register(DS1307_ADDR_YEAR)?;
165
166        let day = match Self::bcd_to_binary(day_raw) {
167            1 => DayOfWeek::Sunday,
168            2 => DayOfWeek::Monday,
169            3 => DayOfWeek::Tuesday,
170            4 => DayOfWeek::Wednesday,
171            5 => DayOfWeek::Thursday,
172            6 => DayOfWeek::Friday,
173            7 => DayOfWeek::Saturday,
174            _ => DayOfWeek::Sunday, // Default fallback
175        };
176
177        Ok(RtcDate {
178            day,
179            date: Self::bcd_to_binary(date),
180            month: Self::bcd_to_binary(month),
181            year: Self::bcd_to_binary(year),
182        })
183    }
184
185    /// Write a value to a DS1307 register
186    fn write_register(&mut self, reg_addr: u8, value: u8) -> Result<()> {
187        let tx_data = [reg_addr, value];
188        self.i2c
189            .master_transmit(DS1307_I2C_ADDRESS, &tx_data, false)
190    }
191
192    /// Read a value from a DS1307 register
193    fn read_register(&mut self, reg_addr: u8) -> Result<u8> {
194        // Send register address
195        self.i2c
196            .master_transmit(DS1307_I2C_ADDRESS, &[reg_addr], true)?;
197
198        // Read the register value
199        let mut data = [0u8; 1];
200        self.i2c
201            .master_receive(DS1307_I2C_ADDRESS, &mut data, false)?;
202
203        Ok(data[0])
204    }
205
206    /// Convert binary value to BCD (Binary Coded Decimal)
207    fn binary_to_bcd(value: u8) -> u8 {
208        if value >= 10 {
209            let tens = value / 10;
210            let ones = value % 10;
211            (tens << 4) | ones
212        } else {
213            value
214        }
215    }
216
217    /// Convert BCD (Binary Coded Decimal) to binary value
218    fn bcd_to_binary(value: u8) -> u8 {
219        let tens = (value >> 4) * 10;
220        let ones = value & 0x0F;
221        tens + ones
222    }
223}
224
225impl<I2C> DS1307<I2C> {
226    /// Release the I2C peripheral and consume the driver
227    pub fn release(self) -> I2C {
228        self.i2c
229    }
230}
231
232// Helper functions for creating date/time structures
233impl RtcDate {
234    /// Create a new RtcDate
235    pub fn new(date: u8, month: u8, year: u8, day: DayOfWeek) -> Self {
236        Self {
237            date,
238            month,
239            year,
240            day,
241        }
242    }
243}
244
245impl RtcTime {
246    /// Create a new RtcTime
247    pub fn new(seconds: u8, minutes: u8, hours: u8, time_format: TimeFormat) -> Self {
248        Self {
249            seconds,
250            minutes,
251            hours,
252            time_format,
253        }
254    }
255}