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