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-2022 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.
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
44namespace fabgl {
45
46
47
50
51
52
53DateTime::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
66void 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!!
75time_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
93DS3231::DS3231()
94 : m_i2c(nullptr),
95 m_available(false),
96 m_dateTimeValid(false)
97{
98}
99
100
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
112uint8_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
121bool 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
158bool 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
203void 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
This file contains the DS3231 (Real Time Clock) device driver.
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
DateTime const & datetime()
Queries DS3231 for current date and time.
Definition: DS3231.cpp:128
void begin(I2C *i2c)
Initializes DS3231 driver.
Definition: DS3231.cpp:101
void clockEnabled(bool value)
Enables or disables DS3231 oscillator.
Definition: DS3231.cpp:203
bool write(int address, uint8_t *buffer, int size, int frequency=100000, int timeOutMS=50)
Sends a buffer to I2C bus.
Definition: tsi2c.cpp:113
int read(int address, uint8_t *buffer, int size, int frequency=100000, int timeOutMS=50)
Receives a buffer from I2C bus.
Definition: tsi2c.cpp:141
I2C class allows multiple tasks to communicate with I2C devices, serializing read/write jobs.
Definition: tsi2c.h:85
int8_t seconds
Definition: DS3231.h:59
int8_t dayOfMonth
Definition: DS3231.h:63
int8_t month
Definition: DS3231.h:64
int8_t minutes
Definition: DS3231.h:60
int8_t hours
Definition: DS3231.h:61
int8_t dayOfWeek
Definition: DS3231.h:62
int16_t year
Definition: DS3231.h:65
Represents date and time.
Definition: DS3231.h:58