FabGL
ESP32 Display Controller and Graphics Library
DS3231.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3  Copyright (c) 2019-2020 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6  This file is part of FabGL Library.
7 
8  FabGL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  FabGL is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 
24 #ifdef ARDUINO
25 
26 
27 #include <string.h>
28 #include <time.h>
29 
30 #include "freertos/FreeRTOS.h"
31 
32 #include "DS3231.h"
33 
34 
35 
36 #define DS3231_ADDR 0x68
37 #define DS3231_FREQ 400000
38 
39 
40 namespace fabgl {
41 
42 
43 
46 
47 
48 
49 DateTime::DateTime(int seconds_, int minutes_, int hours_, int dayOfMonth_, int month_, int year_)
50  : seconds(seconds_),
51  minutes(minutes_),
52  hours(hours_),
53  dayOfMonth(dayOfMonth_),
54  month(month_),
55  year(year_)
56 {
57  calcDayOfWeek();
58 }
59 
60 
61 // 1 = sunday
62 void DateTime::calcDayOfWeek()
63 {
64  static const int8_t t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
65  int y = year - (month < 3);
66  dayOfWeek = 1 + (y + y / 4 - y / 100 + y / 400 + t[month - 1] + dayOfMonth) % 7;
67 }
68 
69 
70 // has 2038 unix bug!!
71 time_t DateTime::timestamp(int timezone)
72 {
73  tm m;
74  m.tm_sec = seconds;
75  m.tm_min = minutes;
76  m.tm_hour = hours;
77  m.tm_mday = dayOfMonth;
78  m.tm_mon = month - 1;
79  m.tm_year = year - 1900;
80  m.tm_isdst = 0;
81  return mktime(&m) - 3600 * timezone;
82 }
83 
84 
87 
88 
89 DS3231::DS3231()
90  : m_i2c(nullptr),
91  m_available(false),
92  m_dateTimeValid(false)
93 {
94 }
95 
96 
97 void DS3231::begin(I2C * i2c)
98 {
99  m_i2c = i2c;
100 
101  // check oscillator stop flag
102  uint8_t status = readReg(0x0F);
103  if (m_available)
104  m_dateTimeValid = (status & 0x80) == 0;
105 }
106 
107 
108 uint8_t DS3231::readReg(int reg)
109 {
110  uint8_t b = reg;
111  m_i2c->write(DS3231_ADDR, &b, 1, DS3231_FREQ);
112  m_available = m_i2c->read(DS3231_ADDR, &b, 1, DS3231_FREQ);
113  return b;
114 }
115 
116 
117 bool DS3231::writeReg(int reg, int value)
118 {
119  uint8_t buf[2] = { (uint8_t)reg, (uint8_t)value };
120  return m_i2c->write(DS3231_ADDR, buf, 2, DS3231_FREQ);
121 }
122 
123 
125 {
126  // read 7 registers starting from reg 0
127  uint8_t b = 0;
128  m_i2c->write(DS3231_ADDR, &b, 1, DS3231_FREQ);
129  uint8_t buf[7];
130  m_available = m_i2c->read(DS3231_ADDR, buf, 7, DS3231_FREQ);
131 
132  // decode
133  if (m_available) {
134  m_datetime.seconds = (buf[0] & 0x0f) + ((buf[0] & 0x70) >> 4) * 10;
135  m_datetime.minutes = (buf[1] & 0x0f) + ((buf[1] & 0x70) >> 4) * 10;
136  m_datetime.hours = (buf[2] & 0x0f) + ((buf[2] & 0x10) >> 4) * 10;
137  if (buf[2] & (1 << 6)) {
138  // 12 hours mode (convert to 24)
139  if (buf[2] & (1 << 5))
140  m_datetime.hours += 12;
141  } else {
142  // 24 hours mode
143  m_datetime.hours += ((buf[2] & 0x20) >> 4) * 10;
144  }
145  m_datetime.dayOfWeek = buf[3] & 7;
146  m_datetime.dayOfMonth = (buf[4] & 0x0f) + ((buf[4] & 0x30) >> 4) * 10;
147  m_datetime.month = (buf[5] & 0x0f) + ((buf[5] & 0x10) >> 4) * 10;
148  m_datetime.year = (buf[6] & 0x0f) + ((buf[6] & 0xf0) >> 4) * 10 + 2000;
149  }
150  return m_datetime;
151 }
152 
153 
154 bool DS3231::setDateTime(DateTime const & value)
155 {
156  // write 7 registers starting from reg 0
157  uint8_t buf[8];
158  buf[0] = 0; // starting reg address
159  buf[1] = (value.seconds % 10) | ((value.seconds / 10) << 4);
160  buf[2] = (value.minutes % 10) | ((value.minutes / 10) << 4);
161  buf[3] = (value.hours % 10) | ((value.hours / 10) << 4); // bit6=0 -> 24 hours mode
162  buf[4] = value.dayOfWeek;
163  buf[5] = (value.dayOfMonth % 10) | ((value.dayOfMonth / 10) << 4);;
164  buf[6] = (value.month % 10) | ((value.month / 10) << 4);
165  buf[7] = ((value.year - 2000) % 10) | (((value.year - 2000) / 10) << 4);
166  m_i2c->write(DS3231_ADDR, buf, 8, DS3231_FREQ);
167 
168  // update oscillator stop flag (make date no more invalid)
169  uint8_t st = readReg(0x0f);
170  writeReg(0x0f, st & 0x7f);
171 
172  return m_available;
173 }
174 
175 
177 {
178  if ((readReg(0x0f) & (0b100)) == 0) {
179  // not busy, force "convert temperature"
180  uint8_t r = readReg(0x0e) | 0x20;
181  writeReg(0x0e, r);
182  // wait for not busy
183  vTaskDelay(2 / portTICK_PERIOD_MS);
184  while ((readReg(0x0f) & (0b100)) != 0 && m_available) {
185  vTaskDelay(1);
186  }
187  }
188 
189  // read 2 registers starting from reg 0x11
190  uint8_t b = 0x11;
191  m_i2c->write(DS3231_ADDR, &b, 1, DS3231_FREQ);
192  uint8_t buf[2];
193  m_available = m_i2c->read(DS3231_ADDR, buf, 2, DS3231_FREQ);
194 
195  return (int8_t)buf[0] + 0.25 * (buf[1] >> 6);
196 }
197 
198 
199 void DS3231::clockEnabled(bool value)
200 {
201  uint8_t r = readReg(0x0e);
202  writeReg(0x0e, value ? (0x7f & r) : (0x80 | r));
203 }
204 
205 
206 } // fdv namespace
207 
208 #endif // #ifdef ARDUINO
int8_t dayOfMonth
Definition: DS3231.h:59
int8_t dayOfWeek
Definition: DS3231.h:58
int16_t year
Definition: DS3231.h:61
int8_t seconds
Definition: DS3231.h:55
This file contains the DS3231 (Real Time Clock) device driver.
int8_t month
Definition: DS3231.h:60
void clockEnabled(bool value)
Enables or disables DS3231 oscillator.
Definition: DS3231.cpp:199
Represents date and time.
Definition: DS3231.h:54
I2C class allows multiple tasks to communicate with I2C devices, serializing read/write jobs...
Definition: tsi2c.h:76
int read(int address, uint8_t *buffer, int size, int frequency=100000, int timeOutMS=50)
Receives a buffer from I2C bus.
Definition: tsi2c.cpp:124
DateTime const & datetime()
Queries DS3231 for current date and time.
Definition: DS3231.cpp:124
Definition: canvas.cpp:31
int8_t hours
Definition: DS3231.h:57
void begin(I2C *i2c)
Initializes DS3231 driver.
Definition: DS3231.cpp:97
int8_t minutes
Definition: DS3231.h:56
double temperature()
Forces DS3231 to read current temperature.
Definition: DS3231.cpp:176
bool setDateTime(DateTime const &value)
Sets current date and time.
Definition: DS3231.cpp:154
bool write(int address, uint8_t *buffer, int size, int frequency=100000, int timeOutMS=50)
Sends a buffer to I2C bus.
Definition: tsi2c.cpp:99