CuVoodoo STM32F1 firmware template
rtc_ds1307.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
22 /* standard libraries */
23 #include <stdint.h> // standard integer types
24 #include <stdio.h> // standard I/O facilities
25 #include <stdlib.h> // general utilities
26 
27 /* STM32 (including CM3) libraries */
28 #include <libopencm3/stm32/rcc.h> // real-time control clock library
29 #include <libopencm3/stm32/gpio.h> // general purpose input output library
30 #include <libopencm3/stm32/i2c.h> // I2C library
31 
32 #include "global.h" // global utilities
33 #include "rtc_ds1307.h" // RTC header and definitions
34 #include "i2c_master.h" // i2c utilities
35 
36 #define RTC_DS1307_I2C_ADDR 0x68
38 void rtc_ds1307_setup(void)
39 {
40  // configure I2C peripheral
41  i2c_master_setup(false); // DS1307 only supports normal mode (up to 100 kHz)
42 }
43 
45 {
46  uint8_t data[1] = {0}; // to read data over I2C
47  const uint8_t address[] = {0x00}; // memory address for data
48  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing CH value
49  return false;
50  }
51  return data[0]&0x80; // return CH bit value to indicate if oscillator is disabled
52 }
53 
55 {
56  uint16_t to_return = 0; // square wave frequency to return (in Hz)
57  uint8_t data[1] = {0}; // to read data over I2C
58  const uint16_t rtc_ds1307_rs[] = {1, 4096, 8192, 32768}; // RS1/RS0 values
59  const uint8_t address[] = {0x07}; // memory address for data
60  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing control register
61  return 0xffff; // error occurred
62  }
63  if (data[0]&0x10) { // verify if the square wave is enabled (SQWE)
64  to_return = rtc_ds1307_rs[data[0]&0x03]; // read RS1/RS0 and get value
65  } else {
66  to_return = 0; // square wave output is disabled
67  }
68  return to_return;
69 }
70 
72 {
73  uint8_t to_return = 0; // seconds to return
74  uint8_t data[1] = {0}; // to read data over I2C
75  const uint8_t address[] = {0x00}; // memory address for data
76  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
77  return 0xff;
78  }
79  to_return = ((data[0]&0x70)>>4)*10+(data[0]&0x0f); // convert BCD coding into seconds
80  return to_return;
81 }
82 
84 {
85  uint8_t to_return = 0; // minutes to return
86  uint8_t data[1] = {0}; // to read data over I2C
87  const uint8_t address[] = {0x01}; // memory address for data
88  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
89  return 0xff;
90  }
91  to_return = (data[0]>>4)*10+(data[0]&0x0f); // convert BCD coding into minutes
92  return to_return;
93 }
94 
95 uint8_t rtc_ds1307_read_hours(void)
96 {
97  uint8_t to_return = 0; // hours to return
98  uint8_t data[1] = {0}; // to read data over I2C
99  const uint8_t address[] = {0x02}; // memory address for data
100  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
101  return 0xff;
102  }
103  if (data[0]&0x40) { // 12 hour mode
104  if (data[0]&0x02) { // PM
105  to_return += 12; // add the 12 hours
106  }
107  to_return += ((data[0]&0x10)>>4)*10; // convert BCD coding into hours (first digit)
108  } else {
109  to_return = ((data[0]&0x30)>>4)*10; // convert BCD coding into hours (first digit)
110  }
111  to_return += (data[0]&0x0f); // convert BCD coding into hours (second digit)
112  return to_return;
113 }
114 
115 uint8_t rtc_ds1307_read_day(void)
116 {
117  uint8_t to_return = 0; // day to return
118  uint8_t data[1] = {0}; // to read data over I2C
119  const uint8_t address[] = {0x03}; // memory address for data
120  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
121  return 0xff;
122  }
123  to_return = (data[0]&0x07); // convert BCD coding into days
124  return to_return;
125 }
126 
127 uint8_t rtc_ds1307_read_date(void)
128 {
129  uint8_t to_return = 0; // date to return
130  uint8_t data[1] = {0}; // to read data over I2C
131  const uint8_t address[] = {0x04}; // memory address for data
132  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
133  return 0xff;
134  }
135  to_return = ((data[0]&0x30)>>4)*10+(data[0]&0x0f); // convert BCD coding into date
136  return to_return;
137 }
138 
140 {
141  uint8_t to_return = 0; // month to return
142  uint8_t data[1] = {0}; // to read data over I2C
143  const uint8_t address[] = {0x05}; // memory address for data
144  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
145  return 0xff;
146  }
147  to_return = ((data[0]&0x10)>>4)*10+(data[0]&0x0f); // convert BCD coding into month
148  return to_return;
149 }
150 
151 uint8_t rtc_ds1307_read_year(void)
152 {
153  uint8_t data[1] = {0}; // to read data over I2C
154  const uint8_t address[] = {0x06}; // memory address for data
155  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
156  return 0xff;
157  }
158  uint8_t to_return = ((data[0]&0xf0)>>4)*10+(data[0]&0x0f); // convert BCD coding into year
159  return to_return;
160 }
161 
162 uint8_t* rtc_ds1307_read_time(void)
163 {
164  static uint8_t time[7] = {0}; // store time {seconds, minutes, hours, day, date, month, year}
165  uint8_t data[7] = {0}; // to read data over I2C
166  const uint8_t address[] = {0x00}; // memory address for data
167  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read all time bytes
168  return NULL; // error occurred
169  }
170  time[0] = ((data[0]&0x70)>>4)*10+(data[0]&0x0f); // convert seconds from BCD
171  time[1] = (data[1]>>4)*10+(data[1]&0x0f); // convert minutes from BCD
172  time[2] = 0; // re-initialize hours
173  if (data[2]&0x40) { // 12 hour mode
174  if (data[2]&0x02) { // PM
175  time[2] += 12; // add the 12 hours
176  }
177  time[2] += ((data[2]&0x10)>>4)*10; // convert BCD coding into hours (first digit)
178  } else {
179  time[2] = ((data[2]&0x30)>>4)*10; // convert BCD coding into hours (first digit)
180  }
181  time[2] += (data[2]&0x0f); // convert BCD coding into hours (second digit)
182  time[3] = (data[3]&0x07); // convert BCD coding into days
183  time[4] = ((data[4]&0x30)>>4)*10+(data[4]&0x0f); // convert BCD coding into date
184  time[5] = ((data[5]&0x10)>>4)*10+(data[5]&0x0f); // convert BCD coding into month
185  time[6] = ((data[6]&0xf0)>>4)*10+(data[6]&0x0f); // convert BCD coding into year
186  return time;
187 }
188 
189 bool rtc_ds1307_read_ram(uint8_t* data, uint8_t start, uint8_t length)
190 {
191  // sanity checks
192  if (data==NULL || length==0) { // nothing to read
193  return false;
194  }
195  if (start>55 || start+length>56) { // out of bounds RAM
196  return false;
197  }
198 
199  const uint8_t address[] = {0x08+start}; // memory address for data
200  return i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // read RAM (starting at 0x08)
201 }
202 
204 {
205  uint8_t data[1] = {0}; // to write CH value data over I2C
206  const uint8_t address[] = {0x00}; // memory address for data
207  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
208  return false;
209  }
210  data[0] |= 0x80; // set CH to disable oscillator
211  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
212 }
213 
215 {
216  uint8_t data[1] = {0}; // to write CH value data over I2C
217  const uint8_t address[] = {0x00}; // memory address for data
218  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
219  return false;
220  }
221  data[0] &= 0x7f; // clear CH to enable oscillator
222  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
223 }
224 
225 bool rtc_ds1307_write_square_wave(uint16_t frequency)
226 {
227  uint8_t data[1] = {0}; // to write control register value data over I2C
228  switch (frequency) { // set RS1/RS0 based on frequency
229  case 0:
230  data[0] = 0;
231  break;
232  case 1:
233  data[0] = 0|(1<<4);
234  break;
235  case 4096:
236  data[0] = 1|(1<<4);
237  break;
238  case 8192:
239  data[0] = 2|(1<<4);
240  break;
241  case 32768:
242  data[0] = 3|(1<<4);
243  break;
244  default: // unspecified frequency
245  return false;
246  }
247  const uint8_t address[] = {0x07}; // memory address for data
248  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
249 }
250 
251 bool rtc_ds1307_write_seconds(uint8_t seconds)
252 {
253  if (seconds>59) {
254  return false;
255  }
256  uint8_t data[1] = {0}; // to read CH value data and write seconds value over I2C
257  const uint8_t address[] = {0x00}; // memory address for data
258  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
259  return false;
260  }
261  data[0] &= 0x80; // only keep CH flag
262  data[0] |= (((seconds/10)%6)<<4)+(seconds%10); // encode seconds in BCD format
263 
264  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with previous CH value
265 }
266 
267 bool rtc_ds1307_write_minutes(uint8_t minutes)
268 {
269  if (minutes>59) {
270  return false;
271  }
272  uint8_t data[1] = {0}; // to write time value
273  data[0] = (((minutes/10)%6)<<4)+(minutes%10); // encode minutes in BCD format
274 
275  const uint8_t address[] = {0x01}; // memory address for data
276  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
277 }
278 
279 bool rtc_ds1307_write_hours(uint8_t hours)
280 {
281  if (hours>24) {
282  return false;
283  }
284  uint8_t data[1] = {0}; // to write time value
285  data[0] = (((hours/10)%3)<<4)+(hours%10); // encode hours in BCD 24h format
286 
287  const uint8_t address[] = {0x02}; // memory address for data
288  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
289 }
290 
291 bool rtc_ds1307_write_day(uint8_t day)
292 {
293  if (day<1 || day>7) {
294  return false;
295  }
296  uint8_t data[1] = {0}; // to write time value
297  data[0] = (day%8); // encode day in BCD format
298 
299  const uint8_t address[] = {0x03}; // memory address for data
300  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
301 }
302 
303 bool rtc_ds1307_write_date(uint8_t date)
304 {
305  if (date<1 || date>31) {
306  return false;
307  }
308  uint8_t data[1] = {0}; // to write time value
309  data[0] = (((date/10)%4)<<4)+(date%10); // encode date in BCD format
310 
311  const uint8_t address[] = {0x04}; // memory address for data
312  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
313 }
314 
315 bool rtc_ds1307_write_month(uint8_t month)
316 {
317  if (month<1 || month>12) {
318  return false;
319  }
320  uint8_t data[1] = {0}; // to write time value
321  data[0] = (((month/10)%2)<<4)+(month%10); // encode month in BCD format
322 
323  const uint8_t address[] = {0x05}; // memory address for data
324  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
325 }
326 
327 bool rtc_ds1307_write_year(uint8_t year)
328 {
329  if (year>99) {
330  return false;
331  }
332  uint8_t data[1] = {0}; // to write time value
333  data[0] = (((year/10)%10)<<4)+(year%10); // encode year in BCD format
334 
335  const uint8_t address[] = {0x06}; // memory address for data
336  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
337 }
338 
339 bool rtc_ds1307_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint8_t year)
340 {
341  uint8_t data[7] = {0}; // to write all time values
342  const uint8_t address[] = {0x00}; // memory address for data
343  // seconds
344  if (seconds>59) {
345  return false;
346  }
347  if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, 1)) { // read seconds with CH value
348  return false;
349  }
350  data[0] &= 0x80; // only keep CH flag
351  data[0] |= (((seconds/10)%6)<<4)+(seconds%10); // encode seconds in BCD format
352  // minutes
353  if (minutes>59) {
354  return false;
355  }
356  data[1] = (((minutes/10)%6)<<4)+(minutes%10); // encode minutes in BCD format
357  // hours
358  if (hours>24) {
359  return false;
360  }
361  data[2] = (((hours/10)%3)<<4)+(hours%10); // encode hours in BCD 24h format
362  // day
363  if (day<1 || day>7) {
364  return false;
365  }
366  data[3] = (day%8); // encode day in BCD format
367  // date
368  if (date<1 || date>31) {
369  return false;
370  }
371  data[4] = (((date/10)%4)<<4)+(date%10); // encode date in BCD format
372  // month
373  if (month<1 || month>12) {
374  return false;
375  }
376  data[5] = (((month/10)%2)<<4)+(month%10); // encode month in BCD format
377  // year
378  if (year>99) {
379  return false;
380  }
381  data[6] = (((year/10)%10)<<4)+(year%10); // encode year in BCD format
382 
383  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
384 }
385 
386 bool rtc_ds1307_write_ram(uint8_t* data, uint8_t start, uint8_t length)
387 {
388  // sanity checks
389  if (data==NULL || length==0) { // nothing to read
390  return false;
391  }
392  if (start>55 || start+length>56) { // out of bounds RAM
393  return false;
394  }
395  const uint8_t address[] = {0x08+start}; // memory address for data
396  return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write RAM (starting at 0x08)
397 }
library to communicate using I2C as master (API)
bool rtc_ds1307_write_date(uint8_t date)
write date into RTC IC
Definition: rtc_ds1307.c:303
bool rtc_ds1307_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint8_t year)
write time into RTC IC
Definition: rtc_ds1307.c:339
bool rtc_ds1307_write_year(uint8_t year)
write year into RTC IC
Definition: rtc_ds1307.c:327
bool rtc_ds1307_oscillator_enable(void)
enable RTC IC oscillator
Definition: rtc_ds1307.c:214
uint16_t rtc_ds1307_read_square_wave(void)
read square wave output frequency (in Hz)
Definition: rtc_ds1307.c:54
bool rtc_ds1307_write_month(uint8_t month)
write month into RTC IC
Definition: rtc_ds1307.c:315
bool rtc_ds1307_write_minutes(uint8_t minutes)
write minutes into RTC IC
Definition: rtc_ds1307.c:267
#define RTC_DS1307_I2C_ADDR
DS1307 I2C address (fixed to 0b1101000)
Definition: rtc_ds1307.c:36
global definitions and methods (API)
uint8_t rtc_ds1307_read_month(void)
read month from RTC IC
Definition: rtc_ds1307.c:139
bool rtc_ds1307_read_ram(uint8_t *data, uint8_t start, uint8_t length)
read user RAM from RTC IC
Definition: rtc_ds1307.c:189
uint8_t rtc_ds1307_read_year(void)
read year from RTC IC
Definition: rtc_ds1307.c:151
uint8_t * rtc_ds1307_read_time(void)
read time from RTC IC
Definition: rtc_ds1307.c:162
uint8_t rtc_ds1307_read_seconds(void)
read seconds from RTC IC
Definition: rtc_ds1307.c:71
bool rtc_ds1307_oscillator_disable(void)
disable RTC IC oscillator
Definition: rtc_ds1307.c:203
bool rtc_ds1307_write_day(uint8_t day)
write day into RTC IC
Definition: rtc_ds1307.c:291
bool rtc_ds1307_write_hours(uint8_t hours)
write hours into RTC IC
Definition: rtc_ds1307.c:279
uint8_t rtc_ds1307_read_date(void)
read date from RTC IC
Definition: rtc_ds1307.c:127
bool rtc_ds1307_write_ram(uint8_t *data, uint8_t start, uint8_t length)
write user RAM from RTC IC
Definition: rtc_ds1307.c:386
bool rtc_ds1307_write_seconds(uint8_t seconds)
write seconds into RTC IC
Definition: rtc_ds1307.c:251
bool i2c_master_read(uint8_t *data, size_t data_size)
read data
Definition: i2c_master.c:152
void i2c_master_setup(bool fast)
setup I2C peripheral
Definition: i2c_master.c:50
uint8_t rtc_ds1307_read_day(void)
read day from RTC IC
Definition: rtc_ds1307.c:115
#define LENGTH(x)
get the length of an array
Definition: global.h:26
bool rtc_ds1307_oscillator_disabled(void)
verify if oscillator is disabled
Definition: rtc_ds1307.c:44
bool i2c_master_write(const uint8_t *data, size_t data_size)
write data
Definition: i2c_master.c:188
library to communicate with the Maxim DS1307 I2C RTC IC (API)
bool rtc_ds1307_write_square_wave(uint16_t frequency)
write square wave output frequency (in Hz)
Definition: rtc_ds1307.c:225
uint8_t rtc_ds1307_read_hours(void)
read hours from RTC IC
Definition: rtc_ds1307.c:95
uint8_t rtc_ds1307_read_minutes(void)
read minutes from RTC IC
Definition: rtc_ds1307.c:83