-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtc_ds1307.c
318 lines (265 loc) · 9.03 KB
/
rtc_ds1307.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*******************************************************************************
* File : rtc_ds1307.c
* Brief : Implementation of APIs for the DS1307 RTC module
* Author : Kyungjae Lee
* Date : Jun 25, 2023
*
* Note : This code includes only the features that are necessary for my
* personal projects.
******************************************************************************/
#include <rtc_ds1307.h>
#include <string.h> /* memset() */
#include <stdint.h>
/* Private function prototypes */
static void DS1307_I2CPinConfig(void);
static void DS1307_I2CConfig(void);
static void DS1307_Write(uint8_t value, uint8_t regAddr);
static uint8_t DS1307_Read(uint8_t regAddr);
static uint8_t BcdToBinary(uint8_t bcd);
static uint8_t BinaryToBcd(uint8_t binary);
/* Global variables */
I2C_Handle_TypeDef gDS1307I2CHandle;
/**
* DS1307_Init()
* Brief : Initializes DS1307 RTC module
* Param : None
* Retval : 0 if setting DS1307_SEC CH bit to 0 was successful (init success),
* 1 otherwise (init fail)
* Note : N/A
*/
uint8_t DS1307_Init(void)
{
/* 1. Initialize the I2C pins */
DS1307_I2CPinConfig();
/* 2. Initialize the I2C peripheral */
DS1307_I2CConfig();
/* 3. Enable the I2C peripheral */
I2C_PeriControl(DS1307_I2C, ENABLE);
/* 4. Set Clock Halt (CH) bit to 0 to initiate time keeping
* Note: At power on, the time keeping will not function until the CH bit
* becomes 0. So, to initiate the time keeping functionality the
* master needs to write 0 to the slave's CH bit.
* For data write logic, see the "I2C Data Bus" section of DS1307
* reference manual.
*/
DS1307_Write(0x0, DS1307_SEC);
/* 5. Read back Clock Halt (CH) bit
* Note: For data read logic, see the "I2C Data Bus" section of DS1307
* reference manual.
*/
uint8_t clockState = DS1307_Read(DS1307_SEC);
return ((clockState >> 7) & 0x1);
}
/**
* DS1307_SetCurrentTime()
* Brief : Sets the DS1307 Seconds, Minutes, Hours registers according to
* the values configured in @rtcTime
* Param : @rtcTime - pointer to the RTC Time structure which contains the
* values configured by the user
* Retval : None
* Note : N/A
*/
void DS1307_SetCurrentTime(RTC_Time_TypeDef *rtcTime)
{
uint8_t secs, hrs;
/* Set seconds -----------------------------------------------------------*/
secs = BinaryToBcd(rtcTime->seconds);
/* Make sure to keep the CH bit (bit[7]) of the Seconds register */
secs &= ~(0x1 << 7);
DS1307_Write(secs, DS1307_SEC);
/* Set minutes -----------------------------------------------------------*/
DS1307_Write(BinaryToBcd(rtcTime->minutes), DS1307_MIN);
/* Set hours -------------------------------------------------------------*/
hrs = BinaryToBcd(rtcTime->hours);
if (rtcTime->timeFormat == TIME_FORMAT_24HRS)
{
/* To use 24HRS time format, clear bit[6] of the Hours register */
hrs &= ~(0x1 << 6);
}
else
{
/* To use 12HRS time format, set bit[6] of the Hours register */
hrs |= (0x1 << 6);
/* If PM, set bit[5] of the Hours register, if AM, clear it */
hrs = (rtcTime->timeFormat == TIME_FORMAT_12HRS_PM) ? hrs | (0x1 << 5) : hrs & ~(0x1 << 5);
}
DS1307_Write(hrs, DS1307_HR);
} /* End of DS1307_SetCurrentTime */
/**
* DS1307_GetCurrentTime()
* Brief : Gets the current time information and stores it into @rtcTime
* Param : @rtcTime - RTC_Time structure to store the current time info
* Retval : None
* Note : N/A
*/
void DS1307_GetCurrentTime(RTC_Time_TypeDef *rtcTime)
{
uint8_t secs, hrs;
/* Get seconds -----------------------------------------------------------*/
secs = DS1307_Read(DS1307_SEC);
secs &= ~(0x1 << 7); /* Exclude unnecessary bits */
rtcTime->seconds = BcdToBinary(secs);
/* Get minutes -----------------------------------------------------------*/
rtcTime->minutes = BcdToBinary(DS1307_Read(DS1307_MIN));
/* Get hours -------------------------------------------------------------*/
hrs = DS1307_Read(DS1307_HR);
if (hrs & (0x1 << 6))
{
/* 12HRS format */
rtcTime->timeFormat = !((hrs & (0x1 << 5)) == 0);
hrs &= ~(0x3 << 5); /* Clear bit[6] and bit[5] */
}
else
{
/* 24HRS format */
rtcTime->timeFormat = TIME_FORMAT_24HRS;
}
rtcTime->hours = BcdToBinary(hrs);
} /* End of DS1307_GetCurrentTime */
/**
* DS1307_SetCurrentDate()
* Brief : Sets the current date information into @rtcDate
* Param : @rtcDate - RTC_Date structure which contains the current date info
* Retval : None
* Note : N/A
*/
void DS1307_SetCurrentDate(RTC_Date_TypeDef *rtcDate)
{
DS1307_Write(BinaryToBcd(rtcDate->date), DS1307_DATE);
DS1307_Write(BinaryToBcd(rtcDate->month), DS1307_MONTH);
DS1307_Write(BinaryToBcd(rtcDate->year), DS1307_YEAR);
DS1307_Write(BinaryToBcd(rtcDate->day), DS1307_DAY);
} /* End of DS1307_SetCurrentDate */
/**
* DS1307_GetCurrentDate()
* Brief : Gets the current date information and stores it into @rtcDate
* Param : @rtcDate - RTC_Date structure to store the current date info
* Retval : None
* Note : N/A
*/
void DS1307_GetCurrentDate(RTC_Date_TypeDef *rtcDate)
{
rtcDate->day = BcdToBinary(DS1307_Read(DS1307_DAY));
rtcDate->date = BcdToBinary(DS1307_Read(DS1307_DATE));
rtcDate->month = BcdToBinary(DS1307_Read(DS1307_MONTH));
rtcDate->year = BcdToBinary(DS1307_Read(DS1307_YEAR));
} /* End of DS1307_GetCurrentDate */
/*******************************************************************************
* Private functions
******************************************************************************/
/**
* DS1307_I2CPinConfig()
* Brief : Configures the GPIO pins to be used for I2C communication
* Param : None
* Retval : None
* Note : N/A
*/
static void DS1307_I2CPinConfig(void)
{
GPIO_Handle_TypeDef i2cSda, i2cScl;
/* Zero-out all the fields in the structures (Very important! i2cSda, i2cScl
* are local variables whose members may be filled with garbage values before
* initialization. These garbage values may set (corrupt) the bit fields that
* you did not touch assuming that they will be 0 by default. Do NOT make this
* mistake!
*/
memset(&i2cSda, 0, sizeof(i2cSda));
memset(&i2cScl, 0, sizeof(i2cScl));
/*
* I2C1_SCL: PB6
* I2C1_SDA: PB7
*/
i2cSda.pGPIOx = DS1307_I2C_GPIO_PORT;
i2cSda.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;
i2cSda.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;
i2cSda.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SDA;
i2cSda.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;
i2cSda.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;
i2cSda.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
GPIO_Init(&i2cSda);
i2cScl.pGPIOx = DS1307_I2C_GPIO_PORT;
i2cScl.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;
i2cScl.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;
i2cScl.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SCL;
i2cScl.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;
i2cScl.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;
i2cScl.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
GPIO_Init(&i2cScl);
} /* End of DS1307_I2CPinConfig */
/**
* DS1307_I2CConfig()
* Brief : Configures and initializes DS1307 I2C peripheral
* Param : None
* Retval : None
* Note : N/A
*/
static void DS1307_I2CConfig(void)
{
gDS1307I2CHandle.pI2Cx = DS1307_I2C;
gDS1307I2CHandle.I2C_Config.I2C_ACKEnable = I2C_ACK_ENABLE;
gDS1307I2CHandle.I2C_Config.I2C_SCLSpeed = DS1307_I2C_SPEED;
I2C_Init(&gDS1307I2CHandle);
} /* End of DS1307_I2CConfig */
/**
* DS1307_Write()
* Brief : Writes @value to @regAddr
* Param : @value - value to write to @regAddr
* @regAddr - DS1307 register address to write @value to
* Retval : None
* Note : N/A
*/
static void DS1307_Write(uint8_t value, uint8_t regAddr)
{
uint8_t tx[2];
tx[0] = regAddr;
tx[1] = value;
I2C_MasterTxBlocking(&gDS1307I2CHandle, tx, 2, DS1307_I2C_ADDR, 0);
} /* End of DS1307_Write */
/**
* DS1307_Read()
* Brief : Writes @value to @regAddr
* Param : @regAddr - DS1307 register address to read from
* Retval : 1-byte data received from the slave (DS1307 RTC module)
* Note : N/A
*/
static uint8_t DS1307_Read(uint8_t regAddr)
{
uint8_t rxData;
I2C_MasterTxBlocking(&gDS1307I2CHandle, ®Addr, 1, DS1307_I2C_ADDR, 0);
I2C_MasterRxBlocking(&gDS1307I2CHandle, &rxData, 1, DS1307_I2C_ADDR, 0);
return rxData;
} /* End of DS1307_Read */
/**
* BcdToBinary()
* Brief : Converts the passed Binary-Coded Decimal (BCD) value to binary
* Param : @bcd - binary-coded decimal value to be converted into binary
* Retval : @bcd in binary representation
* Note : N/A
*/
static uint8_t BcdToBinary(uint8_t bcd)
{
uint8_t tens, ones;
tens = (uint8_t)((bcd >> 4) * 10);
ones = bcd & (uint8_t)0xF;
return tens + ones;
} /* End of BcdToBinary */
/**
* BinaryToBcd()
* Brief : Converts the passed binary value to Binary-Coded Decimal (BCD)
* Param : @binary - binary value to be converted into binary-coded decimal
* Retval : @binary in binary-coded decimal representation
* Note : N/A
*/
uint8_t BinaryToBcd(uint8_t binary)
{
uint8_t tens, ones;
uint8_t bcd;
bcd = binary;
if (binary >= 10)
{
tens = binary / 10;
ones = binary % 10;
bcd = (tens << 4) | ones;
}
return bcd;
} /* End of BinaryToBcd */