Interface DS3231 RTC module with STM32
Today in this tutorial we are going to interface DS3231 RTC module with STM32. The module works on I2C communication protocol, and therefore we need only 2 wires to interface it with the microcontroller.
The following are the features of DS3231 RTC module
- Highly Accurate RTC Completely Manages All Timekeeping Functions
- Real-Time Clock Counts Seconds, Minutes, Hours, Date of the Month, Month, Day of the Week, and Year, with Leap-Year Compensation Valid Up to 2100
- Digital Temp Sensor Output: ±3°C Accuracy
- Register for Aging Trim
- Two Time-of-Day Alarms
- Programmable Square-Wave Output Signal
- Simple Serial Interface Connects to Most Microcontrollers
- Fast (400kHz) I2C Interface
- Battery-Backup Input for Continuous Timekeeping
- 3.3V Operation
In this Tutorial, we are going to cover the RTC and the temperature section. The remaining features like ALARM, and square wave will be covered in upcoming tutorials.Let’s first start by setting up the CubeMx for the I2C.
So, in the setup above, i have enabled the I2C peripheral. Both, the RTC module, and LCD will be connected to this same I2C. The connection is Shown below
There is nothing special about Interfacing DS3231 with any microcontroller. It’s basically a memory device, which we can write the data to and read the data from. Just like any other memory device, we have to do the following in order to perform the read/write operation
- Select the device by sending the device address on the I2C line
- Select the memory address that you want to access
- write/read the data to the address
The following is the picture from the datasheet of the device. It shows the registers available in the DS3231 for writing and reading data.
As I mentioned, in this tutorial we are only going to interface the RTC and temperature part. therefore we are interested in the registers ranging from address 00h to 06h for the clock and date, and 10h 11h for the temperature.
Some Insight into the CODE
First of all I have defined the address of the device as mentioned in it’s datasheet.
The data stored in the TIME and DATE Registers is in the BCD (Binary Coded Decimal) format, so first we need the functions to convert from decimal to bcd and other way around. The following are the functions to do so
Before reading time, we need to set the time. The following function is defined to set the time. The parameters are self explanatory.
We have to convert the decimal values to the corresponding BCD value before writing them to the registers.
I am using
HAL_I2C_Mem_Write to write data directly to the address given. As you can see above, I have used single address (0x00), and written 7 bytes of data to it. This operation is called Multi-Write, and is supported by pretty much every memory device. The address gets incremented automatically, when you write the next byte of data.
This way it is similar to as writing 1 byte of data to each of the first 7 registers (00h to 06h). The function is defined as follows
Get_Time function is used to read the time and date from the module, and save the data into the time structure.
As seen above, HAL_I2C_Mem_Read is used to read the memory address (0x00) directly, and we are reading 7 bytes of data from this address, so 1 byte will be read from the each incremented address. We also need to convert this data into the decimal format before displaying it.
Get_Temp reads the temperature and than returns a float value
As you can see above, we are reading 2 bytes of data from the 0x11 (11h) address. The LSB (temp) needed to be shifted to the right by 6 places as shown in the picture below
Temperature is represented as a 10-bit code with a resolution of 0.25°C and is accessible at location 11h and 12h. The temperature is encoded in two’s complement format. The upper 8 bits, the integer portion, are at location 11h and the lower 2 bits, the fractional portion, are in the upper nibble at location 12h. For example, 00011001 01b = +25.25°C.
The function force_temp_conv forces the conversion of the temperature by writing into the CONV bit of the control register at the location 05h
the main function
We have to set the time once in the main function, and than we can always read the time in the while loop.
One more very important thing. After setting the time, you must flash the code again with the Set_Time function as commented out as shown below
So, just comment out the function and flash again. This is to ensure that, if microcontroller resets, the RTC won’t start from this time again.