232 lines
5.7 KiB
C++
232 lines
5.7 KiB
C++
/*
|
|
* DS3231.cpp
|
|
*
|
|
* Copyright 2017 Christopher B. Liebman
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*
|
|
* Created on: May 21, 2017
|
|
* Author: chris.l
|
|
*/
|
|
|
|
#include "DS3231.h"
|
|
|
|
//#define DEBUG
|
|
#include "Logger.h"
|
|
|
|
DS3231::DS3231()
|
|
{
|
|
}
|
|
|
|
int DS3231::begin()
|
|
{
|
|
dbprintln("DS3231::begin()");
|
|
|
|
delay(2500); // DS3231 may need this on powerup.
|
|
|
|
uint8_t ctrl = 0b00000000; // enable osc/no BBS/no CONV/1hz/SQWV on/no ALRM
|
|
int err = write(DS3231_CONTROL_REG, ctrl); //CONTROL Register Address
|
|
if (err)
|
|
{
|
|
dbprintf("DS3231(): write(DS3231_CONTROL_REG) failed: %d\n", err);
|
|
return -1;
|
|
}
|
|
|
|
delay(100);
|
|
|
|
// set the clock to 24hr format
|
|
uint8_t hr;
|
|
if (read(DS3231_HOUR_REG, &hr))
|
|
{
|
|
dbprintf("DS3231::begin(): read(DS3231_HOUR_REG) failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
// switch to 24hr mode if its not already
|
|
if (hr & _BV(DS3231_AMPM))
|
|
{
|
|
hr &= ~_BV(DS3231_AMPM);
|
|
|
|
if(write(DS3231_HOUR_REG, hr))
|
|
{
|
|
dbprintf("DS3231::begin(): write(DS3231_HOUR_REG, 0x%02x) failed!\n", hr);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t DS3231::fromBCD(uint8_t val)
|
|
{
|
|
return val - 6 * (val >> 4);
|
|
}
|
|
|
|
uint8_t DS3231::toBCD(uint8_t val)
|
|
{
|
|
return val + 6 * (val / 10);
|
|
}
|
|
|
|
int DS3231::readTime(DS3231DateTime& dt)
|
|
{
|
|
|
|
uint8_t count = setupRead(DS3231_SEC_REG, 7);
|
|
if (count != 7)
|
|
{
|
|
dbprintf("DS3231::readTime: setupRead failed! count:%u = 7\n", count);
|
|
Wire.clearWriteError();
|
|
Wire.flush();
|
|
return -1;
|
|
}
|
|
|
|
uint8_t seconds = Wire.read();
|
|
uint8_t minutes = Wire.read();
|
|
uint8_t hours = Wire.read();
|
|
uint8_t day = Wire.read();
|
|
uint8_t date = Wire.read();
|
|
uint8_t month = Wire.read();
|
|
uint8_t year = Wire.read();
|
|
|
|
dbprintf("DS3231::readTime raw month: 0x%02x\n", month);
|
|
|
|
dt.seconds = fromBCD(seconds);
|
|
dt.minutes = fromBCD(minutes);
|
|
dt.hours = fromBCD(hours & DS3231_24HR_MASK);
|
|
dt.day = fromBCD(day);
|
|
dt.date = fromBCD(date);
|
|
dt.month = fromBCD(month & DS3231_MONTH_MASK);
|
|
dt.year = fromBCD(year);
|
|
dt.century = month&DS3231_CENTURY? 1 : 0;
|
|
|
|
if (!dt.isValid())
|
|
{
|
|
dbprintf("DS3231::readTime: result not valid!!!\n");
|
|
Wire.clearWriteError();
|
|
Wire.flush();
|
|
return -1;
|
|
}
|
|
|
|
dbprintf("DS3231::readTime %04u-%02u-%02u %02u:%02u:%02u day:%u century:%u\n",
|
|
dt.year,
|
|
dt.month,
|
|
dt.date,
|
|
dt.hours,
|
|
dt.minutes,
|
|
dt.seconds,
|
|
dt.day,
|
|
dt.century);
|
|
return 0;
|
|
}
|
|
|
|
int DS3231::writeTime(DS3231DateTime &dt)
|
|
{
|
|
dbprintf("DS3231::writeTime %04u-%02u-%02u %02u:%02u:%02u day:%u century:%u\n",
|
|
dt.year,
|
|
dt.month,
|
|
dt.date,
|
|
dt.hours,
|
|
dt.minutes,
|
|
dt.seconds,
|
|
dt.day,
|
|
dt.century);
|
|
|
|
Wire.beginTransmission(DS3231_ADDRESS);
|
|
if (Wire.write(DS3231_SEC_REG) != 1)
|
|
{
|
|
Wire.endTransmission();
|
|
dbprintln("DS3231::writeTime: Wire.write(reg=DS3231_SEC_REG) failed!");
|
|
return -1;
|
|
}
|
|
|
|
int count;
|
|
count = Wire.write(toBCD(dt.seconds));
|
|
count += Wire.write(toBCD(dt.minutes));
|
|
count += Wire.write(toBCD(dt.hours));
|
|
count += Wire.write(toBCD(dt.day));
|
|
count += Wire.write(toBCD(dt.date));
|
|
count += Wire.write(toBCD(dt.month) | (dt.century ? _BV(DS3231_CENTURY) : 0));
|
|
count += Wire.write(toBCD(dt.year));
|
|
if (count != 7)
|
|
{
|
|
dbprintf("DS3231::writeTime: Wire.write() all fields, expected 7 got %u\n", count);
|
|
return -1;
|
|
}
|
|
int err = Wire.endTransmission();
|
|
if (err)
|
|
{
|
|
dbprintf("DS3231::writeTime: Wire.endTransmission() returned: %d\n", err);
|
|
return -1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int DS3231::setupRead(uint8_t reg, uint8_t size)
|
|
{
|
|
Wire.beginTransmission(DS3231_ADDRESS);
|
|
if (Wire.write(reg) != 1)
|
|
{
|
|
Wire.endTransmission();
|
|
dbprintln("DS3231::setupRead: Wire.write(DS3231_CONTROL_REG) failed!");
|
|
return -1;
|
|
}
|
|
int err = Wire.endTransmission();
|
|
|
|
if (err)
|
|
{
|
|
dbprintf("DS3231::setupRead: Wire.endTransmission() returned: %d\n", err);
|
|
return -1;
|
|
}
|
|
|
|
return Wire.requestFrom(DS3231_ADDRESS, (size_t)size);
|
|
}
|
|
|
|
int DS3231::read(uint8_t reg, uint8_t *value)
|
|
{
|
|
size_t count = setupRead(reg, 1);
|
|
count = Wire.requestFrom(DS3231_ADDRESS, (size_t)1);
|
|
*value = Wire.read();
|
|
if (count != 1)
|
|
{
|
|
dbprintf("DS3231::read: Wire.requestFrom() returns %u, expected 1\n", count);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DS3231::write(uint8_t reg, uint8_t value)
|
|
{
|
|
Wire.beginTransmission(DS3231_ADDRESS);
|
|
if (Wire.write(reg) != 1)
|
|
{
|
|
Wire.endTransmission();
|
|
dbprintf("DS3231::write: Wire.write(reg=%d, value=%d) failed!\n", reg, value);
|
|
return -1;
|
|
}
|
|
size_t count;
|
|
count = Wire.write(value);
|
|
if (count != 1)
|
|
{
|
|
dbprintf("DS3231::write: Wire.write(value=%u) returns %u\n", value, count);
|
|
return -1;
|
|
}
|
|
int err = Wire.endTransmission();
|
|
if (err)
|
|
{
|
|
dbprintf("DS3231::write: Wire.endTransmission() returned: %d\n", err);
|
|
return -1;
|
|
}
|
|
return(0);
|
|
}
|