14#define REG_SECONDS 0x00U
15#define REG_STATUS 0x0FU
16#define TIME_REG_COUNT 7U
17#define HOURS_12H_BIT 0x40U
18#define HOURS_PM_BIT 0x20U
19#define STATUS_OSF 0x80U
20#define STATUS_EN32KHZ 0x08U
21#define STATUS_ALARM_FLAGS 0x03U
22#define STATUS_FIXED_ZERO 0x70U
25#define I2C_TRANSIENT_ERRORS (HAL_I2C_ERROR_BERR | HAL_I2C_ERROR_ARLO | HAL_I2C_ERROR_AF | \
26 HAL_I2C_ERROR_OVR | HAL_I2C_ERROR_TIMEOUT)
33static uint8_t decToBcd(uint8_t value)
35 return (uint8_t)(((value / 10U) << 4) | (value % 10U));
43static uint8_t bcdToDec(uint8_t value)
45 return (uint8_t)(((value >> 4) * 10U) + (value & 0x0FU));
53static bool isBcd(uint8_t value)
55 return ((value >> 4) <= 9U) && ((value & 0x0FU) <= 9U);
63static bool isLeapYear(uint16_t year)
65 return ((year % 4U) == 0U && (year % 100U) != 0U) || ((year % 400U) == 0U);
74static uint8_t daysInMonth(uint16_t year, uint8_t month)
76 static const uint8_t days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
78 if (month == 2U && isLeapYear(year)) {
81 return days[month - 1U];
91static int32_t daysFromCivil(int32_t year, int32_t month, int32_t day)
93 int32_t y = (month <= 2) ? year - 1 : year;
94 int32_t era = y / 400;
95 int32_t yearOfEra = y - era * 400;
96 int32_t dayOfYear = (153 * (month + ((month > 2) ? -3 : 9)) + 2) / 5 + day - 1;
97 int32_t dayOfEra = yearOfEra * 365 + yearOfEra / 4 - yearOfEra / 100 + dayOfYear;
99 return era * 146097 + dayOfEra - 719468;
109static void civilFromDays(int32_t days, uint16_t *year, uint8_t *month, uint8_t *day)
111 int32_t z = days + 719468;
112 int32_t era = z / 146097;
113 int32_t dayOfEra = z - era * 146097;
114 int32_t yearOfEra = (dayOfEra - dayOfEra / 1460 + dayOfEra / 36524 - dayOfEra / 146096) / 365;
115 int32_t dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);
116 int32_t mp = (5 * dayOfYear + 2) / 153;
117 int32_t d = dayOfYear - (153 * mp + 2) / 5 + 1;
118 int32_t m = (mp < 10) ? mp + 3 : mp - 9;
119 int32_t y = yearOfEra + era * 400 + ((m <= 2) ? 1 : 0);
133static uint8_t weekdayOf(uint16_t year, uint8_t month, uint8_t day)
135 int32_t days = daysFromCivil(year, month, day);
138 return (uint8_t)(((days + 3) % 7) + 1);
149static bool isTransient(I2C_HandleTypeDef *hi2c, HAL_StatusTypeDef status)
151 if (status == HAL_BUSY || status == HAL_TIMEOUT) {
154 if (status == HAL_ERROR) {
155 return (HAL_I2C_GetError(hi2c) & I2C_TRANSIENT_ERRORS) != 0U;
179 for (attempt = 1U; attempt <= dev->
maxAttempts; attempt++) {
180 HAL_StatusTypeDef status;
190 if (status == HAL_OK) {
196 if (!isTransient(dev->
hi2c, status)) {
227 if (time->
day < 1U || time->
day > daysInMonth(time->
year, time->
month)) {
230 return (time->
hour <= 23U) && (time->
minute <= 59U) && (time->
second <= 59U);
251 days = daysFromCivil(time->
year, time->
month, time->
day);
252 *epochSeconds = ((uint32_t)days * 86400U) + ((uint32_t)time->
hour * 3600U) +
269 uint32_t secondsOfDay;
272 if (time == NULL || epochSeconds < DS3231_EPOCH_MIN || epochSeconds >
DS3231_EPOCH_MAX) {
276 days = (int32_t)(epochSeconds / 86400U);
277 secondsOfDay = epochSeconds % 86400U;
279 civilFromDays(days, &time->
year, &time->
month, &time->
day);
280 time->
weekday = (uint8_t)(((days + 3) % 7) + 1);
281 time->
hour = (uint8_t)(secondsOfDay / 3600U);
282 time->
minute = (uint8_t)((secondsOfDay % 3600U) / 60U);
283 time->
second = (uint8_t)(secondsOfDay % 60U);
304 HAL_StatusTypeDef status;
305 uint8_t statusRegister;
307 if (dev == NULL || hi2c == NULL) {
316 if (status != HAL_OK) {
321 if (transfer(dev,
false, REG_STATUS, &statusRegister, 1U) !=
DS3231_OK) {
324 if ((statusRegister & STATUS_FIXED_ZERO) != 0U) {
345 uint8_t raw[TIME_REG_COUNT];
350 if (dev == NULL || time == NULL) {
354 if (transfer(dev,
false, REG_SECONDS, raw, TIME_REG_COUNT) !=
DS3231_OK) {
363 for (i = 0U; i < TIME_REG_COUNT; i++) {
364 if (i == 2U || i == 3U) {
367 if (!isBcd(raw[i])) {
372 if ((raw[2] & HOURS_12H_BIT) != 0U) {
373 uint8_t hours12 = (uint8_t)(raw[2] & 0x1FU);
375 if (!isBcd(hours12)) {
378 hours12 = bcdToDec(hours12);
379 if (hours12 < 1U || hours12 > 12U) {
382 hours = (uint8_t)((hours12 % 12U) + (((raw[2] & HOURS_PM_BIT) != 0U) ? 12U : 0U));
384 if (!isBcd((uint8_t)(raw[2] & 0x3FU))) {
387 hours = bcdToDec((uint8_t)(raw[2] & 0x3FU));
390 month = bcdToDec(raw[5]);
392 time->
second = bcdToDec(raw[0]);
393 time->
minute = bcdToDec(raw[1]);
395 time->
day = bcdToDec(raw[4]);
421 uint8_t raw[TIME_REG_COUNT];
427 raw[0] = decToBcd(time->
second);
428 raw[1] = decToBcd(time->
minute);
429 raw[2] = decToBcd(time->
hour);
431 raw[4] = decToBcd(time->
day);
432 raw[5] = decToBcd(time->
month);
435 return transfer(dev,
true, REG_SECONDS, raw, TIME_REG_COUNT);
449 if (epochSeconds == NULL) {
496 uint8_t statusRegister;
498 if (dev == NULL || stopped == NULL) {
502 if (transfer(dev,
false, REG_STATUS, &statusRegister, 1U) !=
DS3231_OK) {
505 *stopped = (statusRegister & STATUS_OSF) != 0U;
522 uint8_t statusRegister;
528 if (transfer(dev,
false, REG_STATUS, &statusRegister, 1U) !=
DS3231_OK) {
532 statusRegister = (uint8_t)((statusRegister & STATUS_EN32KHZ) | STATUS_ALARM_FLAGS);
533 return transfer(dev,
true, REG_STATUS, &statusRegister, 1U);
Types, constants and function prototypes of the STM32_DS3231 driver.
DS3231_Status_t ds3231GetEpoch(DS3231_t *dev, uint32_t *epochSeconds)
Read the current time as seconds since 1970-01-01 00:00:00.
DS3231_Status_t ds3231SetTime(DS3231_t *dev, const DS3231_TIME_t *time)
Set the date and time.
DS3231_Status_t ds3231TimeToEpoch(const DS3231_TIME_t *time, uint32_t *epochSeconds)
Convert a date and time to seconds since 1970-01-01 00:00:00 (UTC, no leap seconds).
DS3231_Status_t ds3231EpochToTime(uint32_t epochSeconds, DS3231_TIME_t *time)
Convert seconds since 1970-01-01 00:00:00 (UTC, no leap seconds) to a date and time.
#define DS3231_DEFAULT_MAX_ATTEMPTS
@ DS3231_ERR_INVALID_DATA
#define DS3231_I2C_ADDRESS
#define DS3231_I2C_TIMEOUT_MS
DS3231_Status_t ds3231GetTime(DS3231_t *dev, DS3231_TIME_t *time)
Read the current date and time.
bool ds3231IsTimeValid(const DS3231_TIME_t *time)
Check that a date and time are valid for the DS3231.
DS3231_Status_t ds3231SetEpoch(DS3231_t *dev, uint32_t epochSeconds)
Set the time from seconds since 1970-01-01 00:00:00.
DS3231_Status_t ds3231ClearOscillatorStopFlag(DS3231_t *dev)
Clear the oscillator stop flag.
DS3231_Status_t ds3231IsOscillatorStopped(DS3231_t *dev, bool *stopped)
Find out whether the oscillator has stopped since the flag was last cleared.
DS3231_Status_t ds3231Init(DS3231_t *dev, I2C_HandleTypeDef *hi2c, uint8_t maxAttempts)
Set up a driver handle and check that a DS3231 answers on the bus.
A calendar date and time, always 24-hour clock.
HAL_StatusTypeDef lastStatus