Erriez DS1302 RTC library for Arduino  2.0.0
DS1302 RTC library for Arduino
ErriezDS1302.cpp
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2020 Erriez
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
33 #include "ErriezDS1302.h"
34 
44 ErriezDS1302::ErriezDS1302(uint8_t clkPin, uint8_t ioPin, uint8_t cePin)
45 {
46 #ifdef __AVR
47  _clkPort = digitalPinToPort(clkPin);
48  _ioPort = digitalPinToPort(ioPin);
49  _cePort = digitalPinToPort(cePin);
50 
51  _clkBit = digitalPinToBitMask(clkPin);
52  _ioBit = digitalPinToBitMask(ioPin);
53  _ceBit = digitalPinToBitMask(cePin);
54 #else
55  _clkPin = clkPin;
56  _ioPin = ioPin;
57  _cePin = cePin;
58 #endif
59 }
60 
71 {
72  // Initialize pins
74  DS1302_IO_LOW();
75  DS1302_CE_LOW();
76 
80 
81  // Check zero bits in day week register
82  if (readRegister(DS1302_REG_DAY_WEEK) & 0xF8) {
83  return false;
84  }
85 
86  // Remove write protect
88 
89  // Check write protect bit
91  // Error: RTC write protect bit not cleared
92  return false;
93  }
94 
95  // DS1302 detected
96  return true;
97 }
98 
111 {
112  // Return status CH (Clock Halt) bit from seconds register
114  // RTC clock stopped
115  return false;
116  } else {
117  // RTC clock is running
118  return true;
119  }
120 }
121 
134 bool ErriezDS1302::clockEnable(bool enable)
135 {
136  uint8_t regSeconds;
137 
138  // Read seconds register
139  regSeconds = readRegister(DS1302_REG_SECONDS);
140 
141  // Set or clear HT bit
142  if (enable) {
143  // Clear to enable
144  regSeconds &= ~(1 << DS1302_SEC_CH);
145  } else {
146  // Set to disable
147  regSeconds |= (1 << DS1302_SEC_CH);
148  }
149 
150  // Write seconds register
151  return writeRegister(DS1302_REG_SECONDS, regSeconds);
152 }
153 
160 {
161  struct tm dt;
162  time_t t;
163 
164  // Read time structure
165  if (!read(&dt)) {
166  // RTC read failed
167  return 0;
168  }
169 
170  // Convert date/time struct tm to time_t
171  t = mktime(&dt);
172 
173  // An offset is needed for AVR target
174 #ifdef ARDUINO_ARCH_AVR
175  t += UNIX_OFFSET;
176 #endif
177 
178  // Return Unix epoch UTC
179  return t;
180 }
181 
192 {
193  struct tm *dt;
194 
195  // Subtract UNIX offset for AVR targets
196 #ifdef ARDUINO_ARCH_AVR
197  t -= UNIX_OFFSET;
198 #endif
199 
200  // Convert time_t to date/time struct tm
201  dt = gmtime(&t);
202 
203  // Write date/time to RTC
204  return write(dt);
205 }
206 
219 bool ErriezDS1302::read(struct tm *dt)
220 {
221  uint8_t buffer[DS1302_NUM_CLOCK_REGS];
222 
223  // Read clock date and time registers
224  if (!readBuffer(0x00, buffer, sizeof(buffer))) {
225  memset(dt, 0, sizeof(struct tm));
226  return false;
227  }
228 
229  // Clear dt
230  memset(dt, 0, sizeof(struct tm));
231 
232  // Convert BCD buffer to Decimal
233  dt->tm_sec = bcdToDec(buffer[0] & 0x7F);
234  dt->tm_min = bcdToDec(buffer[1] & 0x7F);
235  dt->tm_hour = bcdToDec(buffer[2] & 0x3F);
236  dt->tm_mday = bcdToDec(buffer[3] & 0x3F);
237  dt->tm_mon = bcdToDec(buffer[4] & 0x1F);
238  dt->tm_wday = bcdToDec(buffer[5] & 0x07);
239  dt->tm_year = bcdToDec(buffer[6]) + 100; // 2000-1900
240 
241  // Month: 0..11
242  if (dt->tm_mon) {
243  dt->tm_mon--;
244  }
245 
246  // Day of the week: 0=Sunday
247  if (dt->tm_wday) {
248  dt->tm_wday--;
249  }
250 
251  // Check buffer for valid data
252  if ((dt->tm_sec > 59) || (dt->tm_min > 59) || (dt->tm_hour > 23) ||
253  (dt->tm_mday < 1) || (dt->tm_mday > 31) || (dt->tm_mon > 11) || (dt->tm_year > 199) ||
254  (dt->tm_wday > 6))
255  {
256  return false;
257  }
258 
259  return true;
260 }
261 
274 bool ErriezDS1302::write(const struct tm *dt)
275 {
276  // Buffer including write protect = 0
277  uint8_t buffer[DS1302_NUM_CLOCK_REGS + 1];
278 
279  // Encode date time from decimal to BCD
280  buffer[0] = decToBcd(dt->tm_sec) & 0x7F; // Clear CH bit in seconds register
281  buffer[1] = decToBcd(dt->tm_min) & 0x7F;
282  buffer[2] = decToBcd(dt->tm_hour) & 0x3F;
283  buffer[3] = decToBcd(dt->tm_mday) & 0x3F;
284  buffer[4] = decToBcd(dt->tm_mon + 1) & 0x1F;
285  buffer[5] = decToBcd(dt->tm_wday + 1) & 0x07;
286  buffer[6] = decToBcd(dt->tm_year % 100);
287  buffer[7] = 0; // Write protect register
288 
289  // Write BCD encoded buffer to RTC registers
290  return writeBuffer(0x00, buffer, sizeof(buffer));
291 }
292 
308 bool ErriezDS1302::setTime(uint8_t hour, uint8_t min, uint8_t sec)
309 {
310  struct tm dt;
311 
312  // Read date/time from RTC
313  read(&dt);
314 
315  // Update time
316  dt.tm_hour = hour;
317  dt.tm_min = min;
318  dt.tm_sec = sec;
319 
320  // Write date/time to RTC
321  return write(&dt);
322 }
323 
339 bool ErriezDS1302::getTime(uint8_t *hour, uint8_t *min, uint8_t *sec)
340 {
341  struct tm dt;
342 
343  // Read date/time from RTC
344  if (!read(&dt)) {
345  return false;
346  }
347 
348  // Set return values
349  *hour = dt.tm_hour;
350  *min = dt.tm_min;
351  *sec = dt.tm_sec;
352 
353  return true;
354 }
355 
377 bool ErriezDS1302::setDateTime(uint8_t hour, uint8_t min, uint8_t sec,
378  uint8_t mday, uint8_t mon, uint16_t year,
379  uint8_t wday)
380 {
381  struct tm dt;
382 
383  // Prepare struct tm
384  dt.tm_hour = hour;
385  dt.tm_min = min;
386  dt.tm_sec = sec;
387  dt.tm_mday = mday;
388  dt.tm_mon = mon - 1;
389  dt.tm_year = year - 1900;
390  dt.tm_wday = wday;
391 
392  // Write date/time to RTC
393  return write(&dt);
394 }
395 
417 bool ErriezDS1302::getDateTime(uint8_t *hour, uint8_t *min, uint8_t *sec,
418  uint8_t *mday, uint8_t *mon, uint16_t *year,
419  uint8_t *wday)
420 {
421  struct tm dt;
422 
423  // Read date/time from RTC
424  if (!read(&dt)) {
425  return false;
426  }
427 
428  // Set return values
429  *hour = dt.tm_hour;
430  *min = dt.tm_min;
431  *sec = dt.tm_sec;
432  *mday = dt.tm_mday;
433  *mon = dt.tm_mon + 1;
434  *year = dt.tm_year + 1900;
435  *wday = dt.tm_wday;
436 
437  return true;
438 }
439 
447 void ErriezDS1302::writeByteRAM(uint8_t addr, uint8_t value)
448 {
449  transferBegin();
450  writeAddrCmd(DS1302_CMD_WRITE_RAM(addr));
451  writeByte(value);
452  transferEnd();
453 }
454 
462 void ErriezDS1302::writeBufferRAM(uint8_t *buf, uint8_t len)
463 {
464  transferBegin();
465  writeAddrCmd(DS1302_CMD_WRITE_RAM_BURST);
466  for (uint8_t i = 0; i < min((int)len, DS1302_NUM_RAM_REGS); i++) {
467  writeByte(*buf++);
468  }
469  transferEnd();
470 }
471 
479 uint8_t ErriezDS1302::readByteRAM(uint8_t addr)
480 {
481  uint8_t value;
482 
483  transferBegin();
484  writeAddrCmd(DS1302_CMD_READ_RAM(addr));
485  value = readByte();
486  transferEnd();
487 
488  return value;
489 }
490 
498 void ErriezDS1302::readBufferRAM(uint8_t *buf, uint8_t len)
499 {
500  transferBegin();
501  writeAddrCmd(DS1302_CMD_READ_RAM_BURST);
502  for (uint8_t i = 0; i < min((int)len, DS1302_NUM_RAM_REGS); i++) {
503  *buf++ = readByte();
504  }
505  transferEnd();
506 }
507 
515 uint8_t ErriezDS1302::bcdToDec(uint8_t bcd)
516 {
517  return (uint8_t)(10 * ((bcd & 0xF0) >> 4) + (bcd & 0x0F));
518 }
519 
527 uint8_t ErriezDS1302::decToBcd(uint8_t dec)
528 {
529  return (uint8_t)(((dec / 10) << 4) | (dec % 10));
530 }
531 
541 uint8_t ErriezDS1302::readRegister(uint8_t reg)
542 {
543  uint8_t value = 0;
544 
545  // Read 8-bit unsigned value from clock register
546  transferBegin();
547  writeAddrCmd(DS1302_CMD_READ_CLOCK_REG(reg));
548  value = readByte();
549  transferEnd();
550 
551  return value;
552 }
553 
567 bool ErriezDS1302::writeRegister(uint8_t reg, uint8_t value)
568 {
569  // Write 8-bit unsigned value to clock register
570  transferBegin();
571  writeAddrCmd((uint8_t)DS1302_CMD_WRITE_CLOCK_REG(reg));
572  writeByte(value);
573  transferEnd();
574 
575  return true;
576 }
577 
593 bool ErriezDS1302::writeBuffer(uint8_t reg, void *buffer, uint8_t writeLen)
594 {
595  if ((reg != 0) || (writeLen != (DS1302_NUM_CLOCK_REGS + 1))) {
596  // Burst command requires all clock registers including write protect
597  return false;
598  }
599 
600  // Write buffer with clock burst command to clock registers
601  transferBegin();
602  writeAddrCmd(DS1302_CMD_WRITE_CLOCK_BURST);
603  for (uint8_t i = 0; i < min((int)writeLen, DS1302_NUM_RAM_REGS); i++) {
604  writeByte(((uint8_t *)buffer)[i]);
605  }
606  transferEnd();
607 
608  return true;
609 }
610 
624 bool ErriezDS1302::readBuffer(uint8_t reg, void *buffer, uint8_t readLen)
625 {
626  if (reg != 0) {
627  // Burst command requires address 0
628  return false;
629  }
630 
631  // Read buffer with clock burst command from clock registers
632  transferBegin();
633  writeAddrCmd(DS1302_CMD_READ_CLOCK_BURST);
634  for (uint8_t i = 0; i < min((int)readLen, DS1302_NUM_RAM_REGS); i++) {
635  ((uint8_t *)buffer)[i] = readByte();
636  }
637  transferEnd();
638 
639  return true;
640 }
641 
642 // -------------------------------------------------------------------------------------------------
643 // Private functions
644 // -------------------------------------------------------------------------------------------------
648 void ErriezDS1302::transferBegin()
649 {
650  DS1302_CLK_LOW();
651  DS1302_IO_LOW();
653  DS1302_CE_HIGH();
654 }
655 
659 void ErriezDS1302::transferEnd()
660 {
661  DS1302_CE_LOW();
662 }
663 
669 void ErriezDS1302::writeAddrCmd(uint8_t value)
670 {
671  // Write 8 bits to RTC
672  for (uint8_t i = 0; i < 8; i++) {
673  if (value & (1 << i)) {
674  DS1302_IO_HIGH();
675  } else {
676  DS1302_IO_LOW();
677  }
679  DS1302_CLK_HIGH();
681 
682  if ((value & (1 << DS1302_BIT_READ)) && (i == 7)) {
683  DS1302_IO_INPUT();
684  } else {
685  DS1302_CLK_LOW();
686  }
687  }
688 }
689 
695 void ErriezDS1302::writeByte(uint8_t value)
696 {
697  // Write 8 bits to RTC
698  for (uint8_t i = 0; i < 8; i++) {
699  if (value & 0x01) {
700  DS1302_IO_HIGH();
701  } else {
702  DS1302_IO_LOW();
703  }
704  value >>= 1;
705  DS1302_CLK_HIGH();
707  DS1302_CLK_LOW();
708  }
709 }
710 
716 uint8_t ErriezDS1302::readByte()
717 {
718  uint8_t value = 0;
719 
720  for (uint8_t i = 0; i < 8; i++) {
721  DS1302_CLK_HIGH();
722  DS1302_CLK_LOW();
724 
725  value >>= 1;
726  if (DS1302_IO_READ()) {
727  value |= 0x80;
728  } else {
729  value &= ~(0x80);
730  }
731  }
732 
733  return value;
734 }
void writeBufferRAM(uint8_t *buf, uint8_t len)
Write buffer to RAM address 0x00 (burst write)
void readBufferRAM(uint8_t *buf, uint8_t len)
Read buffer from RAM address 0x00 (burst read)
bool getTime(uint8_t *hour, uint8_t *min, uint8_t *sec)
Read time from RTC.
bool setEpoch(time_t t)
Write Unix epoch UTC time to RTC.
#define DS1302_BIT_WP
Write protect bit.
Definition: ErriezDS1302.h:80
#define DS1302_CE_HIGH()
CE pin high.
Definition: ErriezDS1302.h:114
#define DS1302_IO_OUTPUT()
IO pin output.
Definition: ErriezDS1302.h:110
ErriezDS1302(uint8_t clkPin, uint8_t ioPin, uint8_t cePin)
Constructor DS1302 RTC.
bool isRunning()
Read RTC CH (Clock Halt) from seconds register.
#define DS1302_IO_LOW()
IO pin low.
Definition: ErriezDS1302.h:107
#define DS1302_CE_OUTPUT()
CE pin output.
Definition: ErriezDS1302.h:116
bool clockEnable(bool enable=true)
Enable or disable oscillator.
#define DS1302_CMD_READ_CLOCK_BURST
DS1302 read clock register with burst.
Definition: ErriezDS1302.h:51
time_t getEpoch()
Read Unix UTC epoch time_t.
uint8_t bcdToDec(uint8_t bcd)
BCD to decimal conversion.
#define DS1302_CE_LOW()
CE pin low.
Definition: ErriezDS1302.h:113
uint8_t readRegister(uint8_t reg)
Read register.
#define DS1302_CLK_OUTPUT()
CLK pin output.
Definition: ErriezDS1302.h:105
bool setTime(uint8_t hour, uint8_t min, uint8_t sec)
Write time to RTC.
#define DS1302_REG_SECONDS
DS1302 registers.
Definition: ErriezDS1302.h:64
#define DS1302_PIN_DELAY()
Delay between pin changes.
Definition: ErriezDS1302.h:123
bool begin()
Initialize and detect DS1302 RTC.
uint8_t readByteRAM(uint8_t addr)
Read byte from RAM.
#define DS1302_IO_INPUT()
IO pin input.
Definition: ErriezDS1302.h:109
#define DS1302_CMD_WRITE_CLOCK_REG(reg)
DS1302 write clock register.
Definition: ErriezDS1302.h:49
#define DS1302_CMD_READ_CLOCK_REG(reg)
DS1302 read clock register.
Definition: ErriezDS1302.h:47
#define DS1302_SEC_CH
DS1302 register bit defines.
Definition: ErriezDS1302.h:79
bool getDateTime(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *mday, uint8_t *mon, uint16_t *year, uint8_t *wday)
Get date time.
bool readBuffer(uint8_t reg, void *buffer, uint8_t len)
Read buffer from RTC clock registers.
#define DS1302_IO_READ()
IO pin read.
Definition: ErriezDS1302.h:111
#define DS1302_CMD_READ_RAM(addr)
DS1302 read RAM register.
Definition: ErriezDS1302.h:55
#define DS1302_CMD_WRITE_CLOCK_BURST
DS1302 writeclock register with burst.
Definition: ErriezDS1302.h:53
#define DS1302_CMD_WRITE_RAM(addr)
DS1302 write RAM register.
Definition: ErriezDS1302.h:57
#define DS1302_CMD_READ_RAM_BURST
DS1302 read RAM register with burst.
Definition: ErriezDS1302.h:59
bool writeBuffer(uint8_t reg, void *buffer, uint8_t len)
Write buffer to RTC clock registers.
bool setDateTime(uint8_t hour, uint8_t min, uint8_t sec, uint8_t mday, uint8_t mon, uint16_t year, uint8_t wday)
Set date time.
#define DS1302_NUM_CLOCK_REGS
DS1302 number of RAM registers.
Definition: ErriezDS1302.h:75
void writeByteRAM(uint8_t addr, uint8_t value)
Write a byte to RAM.
uint8_t decToBcd(uint8_t dec)
Decimal to BCD conversion.
DS1302 RTC library for Arduino.
#define DS1302_BIT_READ
Bit read.
Definition: ErriezDS1302.h:81
bool write(const struct tm *dt)
Write date and time to RTC.
#define DS1302_IO_HIGH()
IO pin high.
Definition: ErriezDS1302.h:108
#define DS1302_CMD_WRITE_RAM_BURST
DS1302 write RAM register with burst.
Definition: ErriezDS1302.h:61
bool read(struct tm *dt)
Read date and time from RTC.
#define DS1302_CLK_HIGH()
CLK pin high.
Definition: ErriezDS1302.h:103
#define DS1302_REG_DAY_WEEK
Day of the week register.
Definition: ErriezDS1302.h:69
bool writeRegister(uint8_t reg, uint8_t value)
Write register.
#define DS1302_REG_WP
Write protect register.
Definition: ErriezDS1302.h:71
#define DS1302_CLK_LOW()
CLK pin low.
Definition: ErriezDS1302.h:102