H753_CPP_I2C_DS3231_RTC_01 1.0
STM32H753 DS3231 real-time clock over I2C, with an AT24C32 EEPROM marker that stops the clock being set twice, built on the STM32_DS3231 and STM32_AT24C32 libraries
Loading...
Searching...
No Matches
DS3231.h File Reference

Types, constants and function prototypes of the STM32_DS3231 driver. More...

#include "main.h"
#include <stdbool.h>
#include <stdint.h>

Go to the source code of this file.

Data Structures

struct  DS3231_TIME_t
 A calendar date and time, always 24-hour clock. More...
 
struct  DS3231_t
 

Macros

#define DS3231_I2C_ADDRESS   (0x68U << 1)
 
#define DS3231_DEFAULT_MAX_ATTEMPTS   3U
 
#define DS3231_I2C_TIMEOUT_MS   100U
 
#define DS3231_YEAR_MIN   2000U
 
#define DS3231_YEAR_MAX   2099U
 
#define DS3231_EPOCH_MIN   946684800U
 
#define DS3231_EPOCH_MAX   4102444799U
 

Enumerations

enum  DS3231_Status_t {
  DS3231_OK = 0 , DS3231_ERR_PARAM , DS3231_ERR_NOT_FOUND , DS3231_ERR_INVALID_DATA ,
  DS3231_ERR_BUS
}
 

Functions

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.
 
DS3231_Status_t ds3231GetTime (DS3231_t *dev, DS3231_TIME_t *time)
 Read the current date and time.
 
DS3231_Status_t ds3231SetTime (DS3231_t *dev, const DS3231_TIME_t *time)
 Set the date and time.
 
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 ds3231SetEpoch (DS3231_t *dev, uint32_t epochSeconds)
 Set the time from seconds since 1970-01-01 00:00:00.
 
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 ds3231ClearOscillatorStopFlag (DS3231_t *dev)
 Clear the oscillator stop flag.
 
bool ds3231IsTimeValid (const DS3231_TIME_t *time)
 Check that a date and time are valid for the DS3231.
 
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.
 

Detailed Description

Types, constants and function prototypes of the STM32_DS3231 driver.

Every function is documented where it is defined, in DS3231.c.

Error handling
A failed HAL I2C read or write is something the program cannot continue from, but only some failures are worth retrying. A transient communication failure (HAL_BUSY, HAL_TIMEOUT, or HAL_ERROR with an I2C error code for a bus problem: bus error, arbitration lost, acknowledge failure, overrun or timeout) is retried: the complete transaction is sent again, up to DS3231_t::maxAttempts times in all. Any other failure, such as HAL_ERROR from a bad parameter or a peripheral in the wrong state, cannot be fixed by trying again and is not retried. Once the attempts are used up, or at once for a failure that is not retried, the driver calls Error_Handler() from main.h, which does not return. DS3231_t::lastStatus holds the HAL status of the most recent failed attempt.

Problems that are the caller's to handle are returned as a DS3231_Status_t instead: a bad argument, a chip that does not answer or does not look like a DS3231 in ds3231Init(), and time registers that hold an impossible date.

Wiring
VCC, GND, SCL and SDA go to the MCU. The ZS-042 module has pull-up resistors on SCL and SDA (and on SQW and 32K) tied to its own VCC, so no external pull-ups are needed.
Warning
Power the ZS-042 from 3.3 V, not 5 V. (1) The module charges its battery pin through a 200 ohm resistor and a diode from VCC; at 5 V that pushes current into a non-rechargeable CR2032, which can leak or swell; at 3.3 V the diode stays reverse-biased. (2) The pull-ups go to the module's VCC, so at 5 V the I2C lines idle at 5 V, which many MCU pins and other bus devices do not tolerate. Both chips work from 3.3 V.
Thread safety and ISR safety
Not thread-safe and not ISR-safe. Every operation is a blocking HAL I2C transaction on a peripheral handle that other code may share, with no lock, and ds3231ClearOscillatorStopFlag() is a read followed by a write. A second caller (another RTOS task, or an interrupt handler) that uses the same I2C peripheral between those steps would interleave with this driver and corrupt both transfers. Call the driver from one context, or put a mutex around every use of the shared I2C handle. Do not call it from an interrupt handler: the HAL calls block and use HAL_Delay() for the retry pause.

Definition in file DS3231.h.

Macro Definition Documentation

◆ DS3231_DEFAULT_MAX_ATTEMPTS

#define DS3231_DEFAULT_MAX_ATTEMPTS   3U

Number of attempts used when ds3231Init() is given 0 for maxAttempts.

Definition at line 76 of file DS3231.h.

Referenced by ds3231Init().

◆ DS3231_EPOCH_MAX

#define DS3231_EPOCH_MAX   4102444799U

Seconds from 1970-01-01 00:00:00 to 2099-12-31 23:59:59: the highest epoch value the driver accepts.

Definition at line 91 of file DS3231.h.

Referenced by ds3231EpochToTime().

◆ DS3231_EPOCH_MIN

#define DS3231_EPOCH_MIN   946684800U

Seconds from 1970-01-01 00:00:00 to 2000-01-01 00:00:00: the lowest epoch value the driver accepts.

Definition at line 88 of file DS3231.h.

◆ DS3231_I2C_ADDRESS

#define DS3231_I2C_ADDRESS   (0x68U << 1)

8-bit (write) I2C address of the DS3231: the 7-bit address 0x68 shifted left, as the HAL expects.

Definition at line 73 of file DS3231.h.

Referenced by ds3231Init().

◆ DS3231_I2C_TIMEOUT_MS

#define DS3231_I2C_TIMEOUT_MS   100U

Timeout, in milliseconds, of one HAL I2C transfer.

Definition at line 79 of file DS3231.h.

Referenced by ds3231Init().

◆ DS3231_YEAR_MAX

#define DS3231_YEAR_MAX   2099U

Last year the driver accepts.

Definition at line 85 of file DS3231.h.

Referenced by ds3231IsTimeValid().

◆ DS3231_YEAR_MIN

#define DS3231_YEAR_MIN   2000U

First year the driver accepts (the chip stores a two-digit year).

Definition at line 82 of file DS3231.h.

Referenced by ds3231GetTime(), ds3231IsTimeValid(), and ds3231SetTime().

Enumeration Type Documentation

◆ DS3231_Status_t

Result of a driver function.

Enumerator
DS3231_OK 

The call succeeded.

DS3231_ERR_PARAM 

A pointer was NULL or a value was outside its valid range.

DS3231_ERR_NOT_FOUND 

Nothing answered at the DS3231 address, or what answered is not a DS3231.

DS3231_ERR_INVALID_DATA 

The time registers hold something that is not a valid date and time.

DS3231_ERR_BUS 

An I2C transfer failed for good. Only returned if Error_Handler() returns.

Definition at line 94 of file DS3231.h.

Function Documentation

◆ ds3231ClearOscillatorStopFlag()

DS3231_Status_t ds3231ClearOscillatorStopFlag ( DS3231_t * dev)

Clear the oscillator stop flag.

Reads the status register and writes it back with OSF cleared and the 32 kHz output setting kept. The two alarm flags are written as 1, which the datasheet says leaves them unchanged, so an alarm that fires between the read and the write is not lost. The read followed by the write is not atomic against other users of the same I2C bus (see the thread-safety note).

Parameters
devThe driver handle, set up with ds3231Init().
Returns
DS3231_OK, or DS3231_ERR_PARAM if dev is NULL.

Definition at line 520 of file DS3231.c.

References DS3231_ERR_BUS, DS3231_ERR_PARAM, DS3231_OK, and ds3231ClearOscillatorStopFlag().

Referenced by ds3231ClearOscillatorStopFlag(), and setClockFromBuildTime().

◆ ds3231EpochToTime()

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.

Pure calculation: it does not touch the chip.

Parameters
epochSecondsSeconds since 1970-01-01 00:00:00, DS3231_EPOCH_MIN to DS3231_EPOCH_MAX.
timeReceives the date and time, with the weekday filled in.
Returns
DS3231_OK, or DS3231_ERR_PARAM if time is NULL or epochSeconds is outside the range the chip can hold (years 2000 to 2099).

Definition at line 267 of file DS3231.c.

References DS3231_TIME_t::day, DS3231_EPOCH_MAX, DS3231_ERR_PARAM, DS3231_OK, ds3231EpochToTime(), DS3231_TIME_t::hour, DS3231_TIME_t::minute, DS3231_TIME_t::month, DS3231_TIME_t::second, DS3231_TIME_t::weekday, and DS3231_TIME_t::year.

Referenced by ds3231EpochToTime(), ds3231SetEpoch(), and setClockFromBuildTime().

◆ ds3231GetEpoch()

DS3231_Status_t ds3231GetEpoch ( DS3231_t * dev,
uint32_t * epochSeconds )

Read the current time as seconds since 1970-01-01 00:00:00.

Parameters
devThe driver handle, set up with ds3231Init().
epochSecondsReceives the seconds since 1970-01-01 00:00:00 (the chip is treated as UTC).
Returns
The result of ds3231GetTime(); DS3231_ERR_PARAM if epochSeconds is NULL.

Definition at line 444 of file DS3231.c.

References DS3231_ERR_PARAM, DS3231_OK, ds3231GetEpoch(), ds3231GetTime(), and ds3231TimeToEpoch().

Referenced by ds3231GetEpoch().

◆ ds3231GetTime()

DS3231_Status_t ds3231GetTime ( DS3231_t * dev,
DS3231_TIME_t * time )

Read the current date and time.

Reads the seven timekeeping registers in one burst, which the chip freezes into a buffer so the values cannot change halfway through. A clock set to 12-hour mode by other code is converted to 24-hour. The weekday is worked out from the date.

Parameters
devThe driver handle, set up with ds3231Init().
timeReceives the date and time.
Returns
DS3231_OK; DS3231_ERR_PARAM if a pointer is NULL; DS3231_ERR_INVALID_DATA if the registers do not hold a valid date and time (typical right after the first power-up, before the clock has ever been set; see ds3231IsOscillatorStopped()).

Definition at line 343 of file DS3231.c.

References DS3231_TIME_t::day, DS3231_ERR_BUS, DS3231_ERR_INVALID_DATA, DS3231_ERR_PARAM, DS3231_OK, DS3231_YEAR_MIN, ds3231GetTime(), ds3231IsTimeValid(), DS3231_TIME_t::hour, DS3231_TIME_t::minute, DS3231_TIME_t::month, DS3231_TIME_t::second, DS3231_TIME_t::weekday, and DS3231_TIME_t::year.

Referenced by ds3231GetEpoch(), ds3231GetTime(), and printTime().

◆ ds3231Init()

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.

Call it after MX_I2Cx_Init(). It checks that something acknowledges the DS3231 address, then reads the status register and checks that bits 6:4, which always read 0 on a DS3231, are 0. It does not change anything on the chip.

Parameters
devThe handle to fill in. Not used by the driver before this call.
hi2cThe HAL I2C handle the chip is on, for example &hi2c1.
maxAttemptsAttempts per transaction before Error_Handler() is called; 0 selects DS3231_DEFAULT_MAX_ATTEMPTS.
Returns
DS3231_OK; DS3231_ERR_PARAM if dev or hi2c is NULL; DS3231_ERR_NOT_FOUND if nothing acknowledged the address (DS3231_t::lastStatus holds the HAL status) or the status register does not look like a DS3231's.

Definition at line 302 of file DS3231.c.

References DS3231_DEFAULT_MAX_ATTEMPTS, DS3231_ERR_BUS, DS3231_ERR_NOT_FOUND, DS3231_ERR_PARAM, DS3231_I2C_ADDRESS, DS3231_I2C_TIMEOUT_MS, DS3231_OK, ds3231Init(), DS3231_t::hi2c, DS3231_t::lastStatus, and DS3231_t::maxAttempts.

Referenced by ds3231Init(), and main().

◆ ds3231IsOscillatorStopped()

DS3231_Status_t ds3231IsOscillatorStopped ( DS3231_t * dev,
bool * stopped )

Find out whether the oscillator has stopped since the flag was last cleared.

The oscillator stop flag (OSF) is set the first time power is applied, and whenever both VCC and the backup battery were too low to keep the oscillator running, so a set flag means the time may be wrong.

Parameters
devThe driver handle, set up with ds3231Init().
stoppedReceives true if the flag is set, false if it is clear.
Returns
DS3231_OK, or DS3231_ERR_PARAM if a pointer is NULL.

Definition at line 494 of file DS3231.c.

References DS3231_ERR_BUS, DS3231_ERR_PARAM, DS3231_OK, and ds3231IsOscillatorStopped().

Referenced by ds3231IsOscillatorStopped(), and reportOscillator().

◆ ds3231IsTimeValid()

bool ds3231IsTimeValid ( const DS3231_TIME_t * time)

Check that a date and time are valid for the DS3231.

The weekday member is not checked: the driver works it out from the date.

Parameters
timeThe date and time to check.
Returns
true if the year is 2000 to 2099, the month and day exist on the calendar (leap years included) and the time is 00:00:00 to 23:59:59. false otherwise, or if time is NULL.

Definition at line 216 of file DS3231.c.

References DS3231_TIME_t::day, DS3231_YEAR_MAX, DS3231_YEAR_MIN, ds3231IsTimeValid(), DS3231_TIME_t::hour, DS3231_TIME_t::minute, DS3231_TIME_t::month, DS3231_TIME_t::second, and DS3231_TIME_t::year.

Referenced by ds3231GetTime(), ds3231IsTimeValid(), ds3231SetTime(), ds3231TimeToEpoch(), and parseBuildTime().

◆ ds3231SetEpoch()

DS3231_Status_t ds3231SetEpoch ( DS3231_t * dev,
uint32_t epochSeconds )

Set the time from seconds since 1970-01-01 00:00:00.

The chip is treated as UTC: the value is stored as the calendar date and time it represents, with no time-zone offset.

Parameters
devThe driver handle, set up with ds3231Init().
epochSecondsSeconds since 1970-01-01 00:00:00, DS3231_EPOCH_MIN to DS3231_EPOCH_MAX.
Returns
The result of ds3231SetTime(); DS3231_ERR_PARAM if epochSeconds is outside the range the chip can hold.

Definition at line 471 of file DS3231.c.

References DS3231_OK, ds3231EpochToTime(), ds3231SetEpoch(), and ds3231SetTime().

Referenced by ds3231SetEpoch().

◆ ds3231SetTime()

DS3231_Status_t ds3231SetTime ( DS3231_t * dev,
const DS3231_TIME_t * time )

Set the date and time.

Writes the seven timekeeping registers in one burst, in 24-hour mode with the century bit clear, and writes the weekday worked out from the date. The oscillator stop flag is not touched: call ds3231ClearOscillatorStopFlag() afterwards if the clock had stopped.

Parameters
devThe driver handle, set up with ds3231Init().
timeThe date and time to set; the weekday member is ignored.
Returns
DS3231_OK; DS3231_ERR_PARAM if a pointer is NULL or the date and time are not valid (see ds3231IsTimeValid()). Nothing is written to the chip in that case.

Definition at line 419 of file DS3231.c.

References DS3231_TIME_t::day, DS3231_ERR_PARAM, DS3231_YEAR_MIN, ds3231IsTimeValid(), ds3231SetTime(), DS3231_TIME_t::hour, DS3231_TIME_t::minute, DS3231_TIME_t::month, DS3231_TIME_t::second, and DS3231_TIME_t::year.

Referenced by ds3231SetEpoch(), ds3231SetTime(), and setClockFromBuildTime().

◆ ds3231TimeToEpoch()

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).

Pure calculation: it does not touch the chip.

Parameters
timeThe date and time; the weekday member is ignored.
epochSecondsReceives the seconds since 1970-01-01 00:00:00.
Returns
DS3231_OK, or DS3231_ERR_PARAM if a pointer is NULL or time is not valid (see ds3231IsTimeValid()).

Definition at line 243 of file DS3231.c.

References DS3231_TIME_t::day, DS3231_ERR_PARAM, DS3231_OK, ds3231IsTimeValid(), ds3231TimeToEpoch(), DS3231_TIME_t::hour, DS3231_TIME_t::minute, DS3231_TIME_t::month, DS3231_TIME_t::second, and DS3231_TIME_t::year.

Referenced by ds3231GetEpoch(), ds3231TimeToEpoch(), and setClockFromBuildTime().