-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrtc_ds1307.c
386 lines (370 loc) · 16.4 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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
/*ds1307 high level api - Reza Ebrahimi v1.0*/
/*this is mcu independent code, no need to change the contents of this file. use low level api to adapt the driver to your mcu of choice*/
#include "rtc_ds1307.h"
static void BCD_to_HEX(uint8_t *data_array, uint8_t array_length); /*turns the bcd numbers from ds1307 into hex*/
static void HEX_to_BCD(uint8_t *data_array, uint8_t array_length); /*turns the hex numbers into bcd, to be written back into ds1307*/
static uint8_t register_current_value; /*used to read current values of ds1307 registers*/
static uint8_t register_new_value; /*used to write values to ds1307 registers*/
static uint8_t snap0_vacancy; /*if snap0_vacancy == OCCUPIED, then a snapshot has been saved on ds1307 RAM and is ready to be read*/
static uint8_t register_default_value[] = { /*used in reset function, contains default zero values*/
DS1307_REGISTER_SECONDS_DEFAULT,
DS1307_REGISTER_MINUTES_DEFAULT,
DS1307_REGISTER_HOURS_DEFAULT,
DS1307_REGISTER_DAY_OF_WEEK_DEFAULT,
DS1307_REGISTER_DATE_DEFAULT,
DS1307_REGISTER_MONTH_DEFAULT,
DS1307_REGISTER_YEAR_DEFAULT,
DS1307_REGISTER_CONTROL_DEFAULT
};
/*ds1307_init function accepts 3 inputs, data_array[7] is the new time settings,
run_state commands ds1307 to run or halt (CLOCK_RUN and CLOCK_HALT), and reset_state
could force reset ds1307 (FORCE_RESET) or checks if ds1307 is reset beforehand
(NO_FORCE_RESET)*/
uint8_t DS1307_init(uint8_t *data_array, uint8_t run_state, uint8_t reset_state)
{
DS1307_I2C_init();
if ((DS1307_init_status_report() == DS1307_NOT_INITIALIZED) || (reset_state == FORCE_RESET))
{
DS1307_run(CLOCK_HALT);
DS1307_reset(ALL); /*everything but the 56 bytes general purpose ram inside ds1307*/
DS1307_reset(RAM); /*fills ds1307 general purpose ram wiith default value*/
DS1307_set(TIME, data_array);
DS1307_run(run_state);
DS1307_init_status_update(); /*now the device is initialized (DS1307_INITIALIZED)*/
return OPERATION_DONE;
}
else
{
DS1307_run(run_state);
return OPERATION_FAILED;
}
}
/*we use 1 byte of ds1307 ram to preserve the initialization status. this function reads that 1 byte*/
uint8_t DS1307_init_status_report()
{
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_INIT_STATUS, ®ister_current_value);
if (register_current_value == DS1307_INITIALIZED)
return DS1307_INITIALIZED;
else
return DS1307_NOT_INITIALIZED;
}
/*this function writes DS1307_INITIALIZED inside DS1307_REGISTER_INIT_STATUS*/
void DS1307_init_status_update()
{
register_new_value = DS1307_INITIALIZED;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_INIT_STATUS, ®ister_new_value);
}
/*function to start or halt the operation of DS1307, using CH control bit in SECONDS register
also preserves the contents of SECONDS register*/
uint8_t DS1307_run(uint8_t run_state)
{
/*preserving the contents of SECONDS register and changing CH bit*/
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
if (run_state == CLOCK_RUN)
{
/*CH=0 runs the clock*/
register_new_value = register_current_value & (~(1 << DS1307_BIT_SETTING_CH));
}
else if (run_state == CLOCK_HALT)
{
/*CH=1 halts the clock*/
register_new_value = register_current_value | (1 << DS1307_BIT_SETTING_CH);
}
else
return OPERATION_FAILED;
/*write the new value back to SECONDS register*/
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
return OPERATION_DONE;
}
/*polls the ds1307 to see if its running*/
uint8_t DS1307_run_state(void)
{
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
if (register_current_value & (1 << DS1307_BIT_SETTING_CH))
return DS1307_IS_RUNNING;
else
return DS1307_IS_STOPPED;
}
/*resets the desired register(s), without affecting run_state*/
void DS1307_reset(uint8_t option)
{
switch (option)
{
case SECOND:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
HEX_to_BCD(®ister_default_value[0], 1);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | register_default_value[0];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
break;
case MINUTE:
HEX_to_BCD(®ister_default_value[1], 1);
register_new_value = register_default_value[1];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, ®ister_new_value);
break;
case HOUR:
HEX_to_BCD(®ister_default_value[2], 1);
register_new_value = register_default_value[2] & (~(1 << DS1307_BIT_SETTING_AMPM));
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_HOURS, ®ister_new_value);
break;
case DAY_OF_WEEK:
HEX_to_BCD(®ister_default_value[3], 1);
register_new_value = register_default_value[3];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DAY_OF_WEEK, ®ister_new_value);
break;
case DATE:
HEX_to_BCD(®ister_default_value[4], 1);
register_new_value = register_default_value[4];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DATE, ®ister_new_value);
break;
case MONTH:
HEX_to_BCD(®ister_default_value[5], 1);
register_new_value = register_default_value[5];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MONTH, ®ister_new_value);
break;
case YEAR:
HEX_to_BCD(®ister_default_value[6], 1);
register_new_value = register_default_value[6];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_YEAR, ®ister_new_value);
break;
case CONTROL:
register_new_value = DS1307_REGISTER_CONTROL_DEFAULT;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
break;
case TIME:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
HEX_to_BCD(®ister_default_value[0], 1);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | register_default_value[0];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
HEX_to_BCD(®ister_default_value[2], 1);
register_default_value[2] &= (~(1 << DS1307_BIT_SETTING_AMPM));
time_i2c_write_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, ®ister_default_value[1], 6);
break;
case ALL: /*everything is reset but the general purpose ram*/
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
HEX_to_BCD(®ister_default_value[0], 1);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | register_default_value[0];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
HEX_to_BCD(®ister_default_value[2], 1);
register_default_value[2] &= (~(1 << DS1307_BIT_SETTING_AMPM));
time_i2c_write_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, ®ister_default_value[1], 7);
break;
case RAM:
for (uint8_t register_address = DS1307_RAM_START; register_address <= DS1307_RAM_END; register_address++)
{
register_new_value = DS1307_RAM_BLOCK_DEFAULT;
time_i2c_write_single(DS1307_I2C_ADDRESS, register_address, ®ister_new_value);
}
break;
default:
break;
}
}
/*function to read internal registers of ds1307, one register at a time or all registers*/
uint8_t DS1307_read(uint8_t option, uint8_t *data_array)
{
switch (option)
{
case SECOND:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
*data_array = register_current_value & (~(1 << DS1307_BIT_SETTING_CH));
BCD_to_HEX(data_array, 1);
break;
case MINUTE:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, ®ister_current_value);
*data_array = register_current_value;
BCD_to_HEX(data_array, 1);
break;
case HOUR:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_HOURS, ®ister_current_value);
*data_array = register_current_value & (~(1 << DS1307_BIT_SETTING_AMPM));
BCD_to_HEX(data_array, 1);
break;
case DAY_OF_WEEK:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DAY_OF_WEEK, ®ister_current_value);
*data_array = register_current_value;
BCD_to_HEX(data_array, 1);
break;
case DATE:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DATE, ®ister_current_value);
*data_array = register_current_value;
BCD_to_HEX(data_array, 1);
break;
case MONTH:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MONTH, ®ister_current_value);
*data_array = register_current_value;
BCD_to_HEX(data_array, 1);
break;
case YEAR:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_YEAR, ®ister_current_value);
*data_array = register_current_value;
BCD_to_HEX(data_array, 1);
break;
case CONTROL:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_current_value);
*data_array = register_current_value;
break;
case TIME:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
data_array[0] = register_current_value & (~(1 << DS1307_BIT_SETTING_CH));
time_i2c_read_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, &data_array[1], 6);
BCD_to_HEX(data_array, 7);
break;
case SNAPSHOT:
/*high level function to load a previously saved snapshot from ds1307 RAM. If there is
no saved snapshots, returns nothing. needs an array of 7 bytes as input to function*/
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SNAP0_VACANCY, &snap0_vacancy);
if (snap0_vacancy == OCCUPIED)
{
time_i2c_read_multi(DS1307_I2C_ADDRESS, DS1307_SNAP0_ADDRESS, data_array, 7);
BCD_to_HEX(data_array, 7);
break;
}
else
return OPERATION_FAILED;
case ALL:
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
data_array[0] = register_current_value & (~(1 << DS1307_BIT_SETTING_CH));
time_i2c_read_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, &data_array[1], 7);
BCD_to_HEX(data_array, 7);
break;
default:
return OPERATION_FAILED;
}
return OPERATION_DONE;
}
/*function to set internal registers of ds1307, one register at a time or all registers*/
uint8_t DS1307_set(uint8_t option, uint8_t *data_array)
{
switch (option)
{
case SECOND:
HEX_to_BCD(data_array, 1);
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
break;
case MINUTE:
HEX_to_BCD(data_array, 1);
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, ®ister_new_value);
break;
case HOUR:
HEX_to_BCD(data_array, 1);
register_new_value = (~(1 << DS1307_BIT_SETTING_AMPM)) & *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_HOURS, ®ister_new_value);
break;
case DAY_OF_WEEK:
HEX_to_BCD(data_array, 1);
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DAY_OF_WEEK, ®ister_new_value);
break;
case DATE:
HEX_to_BCD(data_array, 1);
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_DATE, ®ister_new_value);
break;
case MONTH:
HEX_to_BCD(data_array, 1);
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_MONTH, ®ister_new_value);
break;
case YEAR:
HEX_to_BCD(data_array, 1);
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_YEAR, ®ister_new_value);
break;
case CONTROL:
register_new_value = *data_array;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
break;
case TIME:
HEX_to_BCD(data_array, 7);
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | data_array[0];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
data_array[2] &= (~(1 << DS1307_BIT_SETTING_AMPM));
time_i2c_write_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, &data_array[1], 6);
break;
case ALL:
HEX_to_BCD(data_array, 7);
time_i2c_read_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_current_value);
register_new_value = (register_current_value & (1 << DS1307_BIT_SETTING_CH)) | data_array[0];
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, ®ister_new_value);
data_array[2] &= (~(1 << DS1307_BIT_SETTING_AMPM));
time_i2c_write_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_MINUTES, &data_array[1], 7);
break;
default:
return OPERATION_FAILED;
}
return OPERATION_DONE;
}
/*function to utilize the square wave capability of ds1307 i 5 different modes:
WAVE_OFF, WAVE_1 for 1Hz, WAVE_2 for 4.096KHz, WAVE_3 for 8.192KHz, WAVE_4
for 32.768 KHz*/
uint8_t DS1307_square_wave(uint8_t input)
{
switch (input)
{
case WAVE_OFF:
register_new_value = 0X00;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
return OPERATION_DONE;
case WAVE_1:
register_new_value = 0X10;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
return OPERATION_DONE;
case WAVE_2:
register_new_value = 0X11;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
return OPERATION_DONE;
case WAVE_3:
register_new_value = 0X12;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
return OPERATION_DONE;
case WAVE_4:
register_new_value = 0X13;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_CONTROL, ®ister_new_value);
return OPERATION_DONE;
}
return OPERATION_FAILED;
}
/*high level function to save a snapshot of all the time and control registers to ds1307 RAM.
there is only one slot for time snapshot, and a new save clears the last snapshot.*/
void DS1307_snapshot_save()
{
uint8_t data_array_temporary[7];
time_i2c_read_multi(DS1307_I2C_ADDRESS, DS1307_REGISTER_SECONDS, data_array_temporary, 7);
time_i2c_write_multi(DS1307_I2C_ADDRESS, DS1307_SNAP0_ADDRESS, data_array_temporary, 7);
snap0_vacancy = OCCUPIED;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SNAP0_VACANCY, &snap0_vacancy);
}
/*high level function to clear the sapshot slot on ds1307 RAM*/
void DS1307_snapshot_clear()
{
snap0_vacancy = NOT_OCCUPIED;
time_i2c_write_single(DS1307_I2C_ADDRESS, DS1307_REGISTER_SNAP0_VACANCY, &snap0_vacancy);
}
/*internal function related to this file and not accessible from outside*/
static void BCD_to_HEX(uint8_t *data_array, uint8_t array_length)
{
for (int8_t index = (array_length - 1); index >= 0; index--)
{
data_array[index] = ((data_array[index] >> 4) << 1) + ((data_array[index] >> 4) << 3) + (data_array[index] & 0X0F);
}
}
/*internal function related to this file and not accessible from outside*/
static void HEX_to_BCD(uint8_t *data_array, uint8_t array_length)
{
uint8_t temporary_value;
for (int8_t index = (array_length - 1); index >= 0; index--)
{
temporary_value = 0;
while (((int8_t)data_array[index] - 0X0A) >= 0)
{
temporary_value += 0X10;
data_array[index] -= 0X0A;
}
temporary_value += data_array[index];
data_array[index] = temporary_value;
}
}