ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DS3231RTC.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Adapted from DS3232RTC library for DS3231 RTC chip by Thijs Oppermann
25  * 2014-12-07
26  */
27 
28 #include "DS3231RTC.h"
29 #include "../I2C/I2CMaster.h"
30 #if defined(ARDUINO) && ARDUINO >= 100
31 #include <Arduino.h>
32 #else
33 #include <WProgram.h>
34 #endif
35 
65 // I2C address of the RTC chip (7-bit).
66 #define DS3231_I2C_ADDRESS 0x68
67 
68 // Registers.
69 #define DS3231_SECOND 0x00
70 #define DS3231_MINUTE 0x01
71 #define DS3231_HOUR 0x02
72 #define DS3231_DAY_OF_WEEK 0x03
73 #define DS3231_DATE 0x04
74 #define DS3231_MONTH 0x05
75 #define DS3231_YEAR 0x06
76 #define DS3231_ALARM1_SEC 0x07
77 #define DS3231_ALARM1_MIN 0x08
78 #define DS3231_ALARM1_HOUR 0x09
79 #define DS3231_ALARM1_DAY 0x0A
80 #define DS3231_ALARM2_MIN 0x0B
81 #define DS3231_ALARM2_HOUR 0x0C
82 #define DS3231_ALARM2_DAY 0x0D
83 #define DS3231_CONTROL 0x0E
84 #define DS3231_STATUS 0x0F
85 #define DS3231_AGING_OFFSET 0x10
86 #define DS3231_TEMP_MSB 0x11
87 #define DS3231_TEMP_LSB 0x12
88 
89 // Bits in the DS3231_CONTROL register.
90 #define DS3231_EOSC 0x80
91 #define DS3231_BBSQW 0x40
92 #define DS3231_CONV 0x20
93 #define DS3231_RS_1HZ 0x00
94 #define DS3231_RS_1024HZ 0x08
95 #define DS3231_RS_4096HZ 0x10
96 #define DS3231_RS_8192HZ 0x18
97 #define DS3231_INTCN 0x04
98 #define DS3231_A2IE 0x02
99 #define DS3231_A1IE 0x01
100 
101 // Bits in the DS3231_STATUS register.
102 #define DS3231_OSF 0x80
103 #define DS3231_BB32KHZ 0x40
104 #define DS3231_EN32KHZ 0x08
105 #define DS3231_BSY 0x04
106 #define DS3231_A2F 0x02
107 #define DS3231_A1F 0x01
108 
109 // Alarms 0 and 1
110 #define DS3231_ALARM_0 0x07
111 #define DS3231_ALARM_1 0x0B
112 
125 DS3231RTC::DS3231RTC(I2CMaster &bus, uint8_t oneHzPin)
126  : _bus(&bus)
127  , _oneHzPin(oneHzPin)
128  , prevOneHz(false)
129  , _isRealTime(true)
130  , alarmInterrupts(false) {
131  // Probe the device and configure it for our use.
132  _bus->startWrite(DS3231_I2C_ADDRESS);
133  _bus->write(DS3231_CONTROL);
134  if ( _bus->startRead(DS3231_I2C_ADDRESS, 1) ) {
135  uint8_t value = _bus->read() & DS3231_CONV;
136  if ( oneHzPin != 255 ) {
137  value |= DS3231_BBSQW | DS3231_RS_1HZ;
138  }
139  _bus->startWrite(DS3231_I2C_ADDRESS);
140  _bus->write(DS3231_CONTROL);
141  _bus->write(value);
142  _bus->endWrite();
143  }
144  else {
145  // Did not get an acknowledgement from the RTC chip.
146  _isRealTime = false;
147  }
148 
149  // Configure the 1 Hz square wave pin if required.
150  if ( ( oneHzPin != 255) && _isRealTime ) {
151  pinMode(oneHzPin, INPUT);
152  digitalWrite(oneHzPin, HIGH);
153  }
154 }
155 
167  // If not using a 1 Hz pin or there is no RTC chip available,
168  // then assume that there is an update available.
169  if ( ( _oneHzPin == 255) || !_isRealTime ) {
170  return true;
171  }
172 
173  // The DS3231 updates the internal registers on the falling edge of the
174  // 1 Hz clock. The values should be ready to read on the rising edge.
175  bool value = digitalRead(_oneHzPin);
176  if ( value && !prevOneHz ) {
177  prevOneHz = value;
178  return true;
179  }
180  else {
181  prevOneHz = value;
182  return false;
183  }
184 }
185 
186 inline uint8_t fromBCD(uint8_t value) {
187  return (value >> 4) * 10 + (value & 0x0F);
188 }
189 
190 inline uint8_t fromHourBCD(uint8_t value) {
191  if ( (value & 0x40) != 0 ) {
192  // 12-hour mode.
193  uint8_t result = ( (value >> 4) & 0x01 ) * 10 + (value & 0x0F);
194  if ( (value & 0x20) != 0 ) {
195  return (result == 12) ? 12 : (result + 12); // PM
196  }
197  else {
198  return (result == 12) ? 0 : result; // AM
199  }
200  }
201  else {
202  // 24-hour mode.
203  return fromBCD(value);
204  }
205 }
206 
208  if ( _isRealTime ) {
209  _bus->startWrite(DS3231_I2C_ADDRESS);
210  _bus->write(DS3231_SECOND);
211  if ( _bus->startRead(DS3231_I2C_ADDRESS, 3) ) {
212  value->second = fromBCD( _bus->read() );
213  value->minute = fromBCD( _bus->read() );
214  value->hour = fromHourBCD( _bus->read() );
215  }
216  else {
217  // RTC chip is not responding.
218  value->second = 0;
219  value->minute = 0;
220  value->hour = 0;
221  }
222  }
223  else {
224  RTC::readTime(value);
225  }
226 }
227 
229  if ( !_isRealTime ) {
230  RTC::readDate(value);
231  return;
232  }
233  _bus->startWrite(DS3231_I2C_ADDRESS);
234  _bus->write(DS3231_DATE);
235  if ( _bus->startRead(DS3231_I2C_ADDRESS, 3) ) {
236  value->day = fromBCD( _bus->read() );
237  value->month = fromBCD(_bus->read() & 0x7F); // Strip century bit.
238  value->year = fromBCD( _bus->read() ) + 2000;
239  }
240  else {
241  // RTC chip is not responding.
242  value->day = 1;
243  value->month = 1;
244  value->year = 2000;
245  }
246 }
247 
248 inline uint8_t toBCD(uint8_t value) {
249  return ( (value / 10) << 4 ) + (value % 10);
250 }
251 
252 void DS3231RTC::writeTime(const RTCTime* value) {
253  if ( _isRealTime ) {
254  _bus->startWrite(DS3231_I2C_ADDRESS);
255  _bus->write(DS3231_SECOND);
256  _bus->write( toBCD(value->second) );
257  _bus->write( toBCD(value->minute) );
258  _bus->write( toBCD(value->hour) ); // Changes mode to 24-hour clock.
259  _bus->endWrite();
260  }
261  else {
262  RTC::writeTime(value);
263  }
264 }
265 
266 void DS3231RTC::writeDate(const RTCDate* value) {
267  if ( _isRealTime ) {
268  _bus->startWrite(DS3231_I2C_ADDRESS);
269  _bus->write(DS3231_DATE);
270  _bus->write( toBCD(value->day) );
271  _bus->write( toBCD(value->month) );
272  _bus->write( toBCD(value->year % 100) );
273  _bus->endWrite();
274  }
275  else {
276  RTC::writeDate(value);
277  }
278 }
279 
280 void DS3231RTC::readAlarm(uint8_t alarmNum, RTCAlarm* value) {
281  if ( _isRealTime ) {
282  uint8_t reg_value = readRegister(DS3231_CONTROL);
283  _bus->startWrite(DS3231_I2C_ADDRESS);
284  if ( 0 == alarmNum ) {
285  _bus->write(DS3231_ALARM_0);
286  if ( _bus->startRead(DS3231_I2C_ADDRESS, 4) ) {
287  alarmSecondValues(_bus->read(), value);
288  alarmMinuteValues(_bus->read(), value);
289  alarmHourValues(_bus->read(), value);
290  alarmDayValues(_bus->read(), value);
291  value->flags &= ~0x80;
292  value->flags |= (reg_value & 0x01) << 6;
293  }
294  else {
295  // RTC chip is not responding.
296  value->day = 0;
297  value->hour = 0;
298  value->minute = 0;
299  value->second = 0;
300  }
301  }
302  else if ( 1 == alarmNum ) {
303  _bus->write(DS3231_ALARM_1);
304  if ( _bus->startRead(DS3231_I2C_ADDRESS, 3) ) {
305  value->second = 0;
306  alarmMinuteValues(_bus->read(), value);
307  alarmHourValues(_bus->read(), value);
308  alarmDayValues(_bus->read(), value);
309  value->flags |= 0x80;
310  value->flags |= (reg_value & 0x02) << 5;
311  }
312  else {
313  // RTC chip is not responding.
314  value->day = 0;
315  value->hour = 0;
316  value->minute = 0;
317  value->second = 0;
318  }
319  }
320  }
321  else {
322  RTC::readAlarm(alarmNum, value);
323  }
324 }
325 
326 void DS3231RTC::alarmSecondValues(uint8_t read_value, RTCAlarm* value) {
327  uint8_t mask_bit = (read_value & 0x80) ? 0x01 : 0x00;
328 
329  value->second = fromBCD(read_value & 0x7F);
330  value->flags |= mask_bit;
331 }
332 
333 void DS3231RTC::alarmMinuteValues(uint8_t read_value, RTCAlarm* value) {
334  uint8_t mask_bit = (read_value & 0x80) ? 0x02 : 0x00;
335 
336  value->minute = fromBCD(read_value & 0x7F);
337  value->flags |= mask_bit;
338 }
339 
340 void DS3231RTC::alarmHourValues(uint8_t read_value, RTCAlarm* value) {
341  uint8_t mask_bit = (read_value & 0x80) ? 0x04 : 0x00;
342  uint8_t is_ampm = read_value & 0x40;
343 
344  if ( is_ampm ) {
345  uint8_t hour = fromBCD(read_value & ~0xE0);
346  if ( read_value & 0x20 ) {
347  hour += 12;
348  }
349  value->hour = hour;
350  }
351  else {
352  value->hour = fromBCD(read_value & ~0xC0);
353  }
354  value->flags |= mask_bit;
355 }
356 
357 void DS3231RTC::alarmDayValues(uint8_t read_value, RTCAlarm* value) {
358  uint8_t mask_bit = (read_value & 0x80) ? 0x08 : 0x00;
359  uint8_t is_dow = read_value & 0x40;
360 
361  if ( is_dow ) {
362  value->day = 0;
363  value->dow = fromBCD(read_value & 0x0F);
364  value->flags |= 0x20;
365  }
366  else {
367  value->dow = 0;
368  value->day = fromBCD(read_value & 0x3F);
369  value->flags &= ~0x20;
370  }
371  value->flags |= mask_bit;
372 }
373 
374 void DS3231RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm* value) {
375  setAlarm(alarmNum, value);
376  return;
377 }
378 
379 void DS3231RTC::clearAlarm(uint8_t alarmNum) {
380  if ( 0 == alarmNum ) {
381  _bus->startWrite(DS3231_I2C_ADDRESS);
382  _bus->write(DS3231_ALARM_0);
383  _bus->write(0);
384  _bus->write(0);
385  _bus->write(0);
386  _bus->write(0x41);
387  _bus->endWrite();
388  }
389  else if ( 1 == alarmNum ) {
390  _bus->startWrite(DS3231_I2C_ADDRESS);
391  _bus->write(DS3231_ALARM_1);
392  _bus->write(0);
393  _bus->write(0);
394  _bus->write(0x41);
395  _bus->endWrite();
396  }
397 }
398 
408 bool DS3231RTC::setAlarm(uint8_t alarmNum, const RTCAlarm* value) {
409  if ( _isRealTime ) {
410  uint8_t alarm_mask_bits = value->flags;
411 
412  if ( 0 == alarmNum ) {
413  if ( alarm_mask_bits & 0x80 ) {
414  return false;
415  }
416 
417  _bus->startWrite(DS3231_I2C_ADDRESS);
418  _bus->write(DS3231_ALARM_0);
419  _bus->write( toBCD(value->second) | ( ( alarm_mask_bits & 0x01 ) << 7 ) );
420  _bus->write( toBCD(value->minute) | ( ( alarm_mask_bits & 0x02 ) << 6 ) );
421  // only support writing 24h
422  _bus->write( toBCD(value->hour) | ( ( alarm_mask_bits & 0x04 ) << 5 ) );
423  _bus->write( getAlarmDayValue(value) );
424  _bus->endWrite();
425  if ( value->flags & 0x40 ) {
426  enableAlarm(alarmNum);
427  }
428  }
429  else if ( 1 == alarmNum ) {
430  if ( !(alarm_mask_bits & 0x80) ) {
431  return false;
432  }
433 
434  _bus->startWrite(DS3231_I2C_ADDRESS);
435  _bus->write(DS3231_ALARM_1);
436  _bus->write( toBCD(value->minute) | ( ( alarm_mask_bits & 0x02 ) << 6 ) );
437  // only support writing 24h
438  _bus->write( toBCD(value->hour) | ( ( alarm_mask_bits & 0x04 ) << 5 ) );
439  _bus->write( getAlarmDayValue(value) );
440  _bus->endWrite();
441  if ( value->flags & 0x40 ) {
442  enableAlarm(alarmNum);
443  }
444  }
445  }
446  else {
447  RTC::writeAlarm(alarmNum, value);
448  return false;
449  }
450 
451  return true;
452 }
453 
454 uint8_t DS3231RTC::getAlarmDayValue(const RTCAlarm* value) {
455  uint8_t alarm_mask_bits = value->flags;
456  uint8_t day_value_mask = ( alarm_mask_bits & 0x08 ) << 4;
457 
458  if ( alarm_mask_bits & 0x20 ) {
459  // day of week
460  day_value_mask |= 0x40;
461  return (toBCD(value->dow) | day_value_mask);
462  }
463  else {
464  // date
465  day_value_mask &= ~0x40;
466  return (toBCD(value->day) | day_value_mask);
467  }
468 }
469 
471  if ( _isRealTime ) {
472  return ( ( (int)(signed char)readRegister(DS3231_TEMP_MSB) ) << 2 ) |
473  (readRegister(DS3231_TEMP_LSB) >> 6);
474  }
475  else {
476  return NO_TEMPERATURE;
477  }
478 }
479 
495  if ( ( _oneHzPin == 255) && _isRealTime ) {
496  uint8_t value = readRegister(DS3231_CONTROL);
497  value |= DS3231_INTCN;
498  writeRegister(DS3231_CONTROL, value);
499  alarmInterrupts = true;
500  }
501 }
502 
509  if ( alarmInterrupts ) {
510  uint8_t value = readRegister(DS3231_CONTROL);
511  value &= ~(DS3231_INTCN | DS3231_A2IE | DS3231_A1IE);
512  writeRegister(DS3231_CONTROL, value);
513  alarmInterrupts = false;
514  }
515 }
516 
531  if ( !_isRealTime ) {
532  return -1;
533  }
534  uint8_t value = readRegister(DS3231_STATUS);
535  int alarm;
536  if ( value & DS3231_A1F ) {
537  if ( value & DS3231_A2F ) {
538  alarm = 2;
539  }
540  else {
541  alarm = 0;
542  }
543  }
544  else if ( value & DS3231_A2F ) {
545  alarm = 1;
546  }
547  else {
548  alarm = -1;
549  }
550  if ( alarm != -1 ) {
551  value &= ~(DS3231_A1F | DS3231_A2F);
552  writeRegister(DS3231_STATUS, value);
553  }
554  return alarm;
555 }
556 
563  if ( _isRealTime ) {
564  uint8_t value = readRegister(DS3231_STATUS);
565  value |= DS3231_BB32KHZ | DS3231_EN32KHZ;
566  writeRegister(DS3231_STATUS, value);
567  }
568 }
569 
576  if ( _isRealTime ) {
577  uint8_t value = readRegister(DS3231_STATUS);
578  value &= ~(DS3231_BB32KHZ | DS3231_EN32KHZ);
579  writeRegister(DS3231_STATUS, value);
580  }
581 }
582 
583 uint8_t DS3231RTC::readRegister(uint8_t reg) {
584  _bus->startWrite(DS3231_I2C_ADDRESS);
585  _bus->write(reg);
586  if ( !_bus->startRead(DS3231_I2C_ADDRESS, 1) ) {
587  return 0; // RTC chip is not responding.
588  }
589  return _bus->read();
590 }
591 
592 bool DS3231RTC::writeRegister(uint8_t reg, uint8_t value) {
593  _bus->startWrite(DS3231_I2C_ADDRESS);
594  _bus->write(reg);
595  _bus->write(value);
596  return _bus->endWrite();
597 }
598 
606 void DS3231RTC::enableAlarm(uint8_t alarmNum) {
607  uint8_t value = readRegister(DS3231_CONTROL);
608 
609  if ( 0 == alarmNum ) {
610  value |= DS3231_A1IE;
611  }
612  else if ( 1 == alarmNum ) {
613  value |= DS3231_A2IE;
614  }
615  writeRegister(DS3231_CONTROL, value);
616 }
617 
625 void DS3231RTC::disableAlarm(uint8_t alarmNum) {
626  uint8_t value = readRegister(DS3231_CONTROL);
627 
628  clearAlarm(alarmNum);
629 
630  if ( 0 == alarmNum ) {
631  value &= ~DS3231_A1IE;
632  }
633  else if ( 1 == alarmNum ) {
634  value &= ~DS3231_A2IE;
635  }
636  writeRegister(DS3231_CONTROL, value);
637 }
uint8_t month
Month of the year (1-12)
Definition: RTC.h:38
virtual void writeTime(const RTCTime *value)
Updates the time in the realtime clock to match value.
Definition: RTC.cpp:179
void enable32kHzOutput()
Enables the 32 kHz output on the DS3231 chip.
Definition: DS3231RTC.cpp:562
void disableAlarmInterrupts()
Disables the generation of interrupts for alarms 0 and 1.
Definition: DS3231RTC.cpp:508
uint8_t minute
Minute within the hour (0-59)
Definition: RTC.h:31
virtual void readAlarm(uint8_t alarmNum, RTCAlarm *value)
Reads the details of the alarm with index alarmNum into value.
Definition: RTC.cpp:209
virtual void readDate(RTCDate *value)
Reads the current date from the realtime clock into value.
Definition: RTC.cpp:169
uint8_t day
Day of the month for the alarm if not zero.
Definition: RTC.h:44
void readDate(RTCDate *value)
Reads the current date from the realtime clock into value.
Definition: DS3231RTC.cpp:228
int readTemperature()
Reads the value of the temperature sensor and returns the temperature in quarters of a degree celcius...
Definition: DS3231RTC.cpp:470
virtual void write(uint8_t value)=0
Writes a single byte value on the I2C bus.
virtual void writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
Updates the details of the alarm with index alarmNum from value.
Definition: RTC.cpp:224
void enableAlarmInterrupts()
Enables the generation of interrupts for alarms 0 and 1.
Definition: DS3231RTC.cpp:494
virtual void writeDate(const RTCDate *value)
Updates the date in the realtime clock to match value.
Definition: RTC.cpp:194
virtual bool startRead(unsigned int address, unsigned int count)=0
Starts a read operation for count bytes by sending the start condition and the I2C control byte...
uint8_t hour
Hour of the day for the alarm (0-23).
Definition: RTC.h:46
static const int NO_TEMPERATURE
Value that is returned from readTemperature() if the realtime clock chip cannot determine the tempera...
Definition: RTC.h:86
uint8_t flags
Additional flags for the alarm.
Definition: RTC.h:49
void enableAlarm(uint8_t alarmNum)
Enables a specific alarm.
Definition: DS3231RTC.cpp:606
uint8_t dow
Day of the week for the alarm if not zero.
Definition: RTC.h:45
Stores date information from a realtime clock chip.
Definition: RTC.h:35
void readAlarm(uint8_t alarmNum, RTCAlarm *value)
Reads the details of the alarm with index alarmNum into value.
Definition: DS3231RTC.cpp:280
DS3231RTC(I2CMaster &bus, uint8_t oneHzPin=255)
Attaches to a realtime clock slave device on bus.
Definition: DS3231RTC.cpp:125
virtual void startWrite(unsigned int address)
Starts a write operation by sending a start condition and the I2C control byte.
void disableAlarm(uint8_t alarmNum)
Disables a specific alarm.
Definition: DS3231RTC.cpp:625
bool setAlarm(uint8_t alarmNum, const RTCAlarm *value)
Sets the alarm with index alarmNum from value.
Definition: DS3231RTC.cpp:408
virtual bool endWrite()=0
Ends the current write operation.
unsigned int year
Year (4-digit)
Definition: RTC.h:37
void writeDate(const RTCDate *value)
Updates the date in the realtime clock to match value.
Definition: DS3231RTC.cpp:266
void writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
Updates the details of the alarm with index alarmNum from value.
Definition: DS3231RTC.cpp:374
uint8_t minute
Minute of the hour for the alarm (0-59).
Definition: RTC.h:47
void disable32kHzOutput()
Disables the 32 kHz output on the DS3231 chip.
Definition: DS3231RTC.cpp:575
uint8_t second
Second of the minute for the alarm (0-59).
Definition: RTC.h:48
Stores time information from a realtime clock chip.
Definition: RTC.h:28
void writeTime(const RTCTime *value)
Updates the time in the realtime clock to match value.
Definition: DS3231RTC.cpp:252
Abstract base class for I2C master implementations.
Definition: I2CMaster.h:28
Stores alarm information from a realtime clock chip.
Definition: RTC.h:42
bool hasUpdates()
Returns true if there are updates.
Definition: DS3231RTC.cpp:166
virtual uint8_t read()=0
Reads a single byte from the I2C bus.
uint8_t hour
Hour of the day (0-23)
Definition: RTC.h:30
void readTime(RTCTime *value)
Reads the current time from the realtime clock into value.
Definition: DS3231RTC.cpp:207
uint8_t day
Day of the month (1-31)
Definition: RTC.h:39
uint8_t second
Second within the minute (0-59)
Definition: RTC.h:32
int firedAlarm()
Determines which of alarms 0 or 1 have fired since the last call.
Definition: DS3231RTC.cpp:530
virtual void readTime(RTCTime *value)
Reads the current time from the realtime clock into value.
Definition: RTC.cpp:144