Subversion Repositories idreammicro-avr

Rev

Rev 62 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 jlesech 1
/**************************************************************************//**
2
 * \brief DS1307 RTC library
3
 * \author Copyright (C) 2009  Julien Le Sech - www.idreammicro.com
4
 * \version 1.0
5
 * \date 20090501
6
 *
7
 * This file is part of the iDreamMicro library.
8
 *
9
 * This library is free software: you can redistribute it and/or modify it under
10
 * the terms of the GNU Lesser General Public License as published by the Free
11
 * Software Foundation, either version 3 of the License, or (at your option) any
12
 * later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but WITHOUT
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17
 * details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program. If not, see http://www.gnu.org/licenses/
21
 ******************************************************************************/
22
 
23
/**************************************************************************//**
24
 * \file ds1307.c
25
 ******************************************************************************/
26
 
27
/******************************************************************************
28
 * Header file inclusions.
29
 ******************************************************************************/
30
 
31
#include <ds1307/ds1307.h>
32
 
33
#include <twi/twi.h>
62 jlesech 34
#include <useful/bits.h>
18 jlesech 35
#include <useful/datetime.h>
36
 
62 jlesech 37
#include <avr/io.h>
38
 
18 jlesech 39
#include <assert.h>
62 jlesech 40
#include <stdbool.h>
18 jlesech 41
#include <stdlib.h>
42
 
43
/******************************************************************************
44
 * Private macros.
45
 ******************************************************************************/
46
 
62 jlesech 47
#define DS1307__ADDRESS     0xD0
18 jlesech 48
 
62 jlesech 49
#define DS1307__REG_SECONDS     0x00
50
#define DS1307__REG_MINUTES 0x01
51
#define DS1307__REG_HOURS   0x02
52
#define DS1307__REG_DAY     0x03
53
#define DS1307__REG_DATE    0x04
54
#define DS1307__REG_MONTH   0x05
55
#define DS1307__REG_YEAR    0x06
56
#define DS1307__REG_CONTROL 0x07
18 jlesech 57
 
62 jlesech 58
#define DS1307__RS0         0x00
59
#define DS1307__RS1         0x01
60
#define DS1307__SQWE        0x04
61
#define DS1307__OUT         0x07
62
 
63
/**************************************************************************//**
64
 * \def     DS1307__REG_RAM
65
 * \brief   Start address of RAM registers (locations 0x08 to 0x3F).
66
 ******************************************************************************/
67
#define DS1307__REG_RAM       0x08
68
 
18 jlesech 69
/******************************************************************************
70
 * Public function definitions.
71
 ******************************************************************************/
72
 
73
/**************************************************************************//**
74
 * \fn void ds1307__initialize(void)
75
 *
76
 * \brief Initialize RTC.
77
 ******************************************************************************/
78
void
79
ds1307__initialize
80
(
81
    void
82
){
36 jlesech 83
    // We don't initialize TWI here: we may have several devices on the bus.
18 jlesech 84
    // Initialize TWI.
36 jlesech 85
    //twi__initialize(DS1307__CLOCK_RATE);
18 jlesech 86
}
87
 
88
/**************************************************************************//**
89
 * \fn void ds1307__get_time(
90
 * date_time__time_t*   p_time,
91
 * ds1307__hour_mode_t* p_hour_mode)
92
 *
93
 * \brief Get RTC time.
94
 *
95
 * \param p_time a pointer to fill with RTC time
96
 * \param p_hour_mode a pointer to fill with RTC hour mode
97
 ******************************************************************************/
98
void
99
ds1307__get_time
100
(
101
    datetime__time_t*      p_time,
102
    ds1307__hour_mode_t*    p_hour_mode
103
){
104
    // Check the preconditions.
105
    assert(NULL != p_time);
106
    assert(NULL != p_hour_mode);
107
 
108
    twi__start();
58 jlesech 109
    twi__send_slaw(DS1307__ADDRESS);
62 jlesech 110
    twi__send_data(DS1307__REG_SECONDS);
18 jlesech 111
    twi__stop();
112
 
113
    twi__start();
58 jlesech 114
    twi__send_slar(DS1307__ADDRESS);
18 jlesech 115
    uint8_t seconds = 0;
116
    twi__receive_data_ack(&seconds);
117
    uint8_t minutes = 0;
118
    twi__receive_data_ack(&minutes);
119
    uint8_t hours = 0;
120
    twi__receive_data_nack(&hours);
121
    p_time->seconds = (((seconds & 0x70) >> 4) * 10) + (seconds & 0x0F);
122
    p_time->minutes = (((minutes & 0x70) >> 4) * 10) + (minutes & 0x0F);
123
    *p_hour_mode = (ds1307__hour_mode_t)((hours & 0x40) >> 6);
124
    if (DS1307__HOUR_MODE__12_HOUR == *p_hour_mode)
125
    {
126
        p_time->meridiem = (datetime__meridiem_t)((hours & 0x20) >> 5);
127
        p_time->hours = (((hours & 0x10) >> 4) * 10) + (hours & 0x0F);
128
    }
129
    else
130
    {
131
        p_time->hours = (((hours & 0x30) >> 4) * 10) + (hours & 0x0F);
132
    }
133
    twi__stop();
134
}
135
 
136
/**************************************************************************//**
137
 * \fn void ds1307__set_time(
138
 * date_time__time_t* p_time,
139
 * ds1307__hour_mode_t hour_mode)
140
 *
141
 * \brief Set RTC time.
142
 *
143
 * \param p_time time to set. p_time->meridiem isn't used in 12-hour mode.
144
 * \param hour_mode hour mode
145
 ******************************************************************************/
146
void
147
ds1307__set_time
148
(
149
    datetime__time_t*  p_time,
150
    ds1307__hour_mode_t hour_mode
151
){
152
    // Check the preconditions.
153
    assert(NULL != p_time);
154
 
155
    twi__start();
58 jlesech 156
    twi__send_slaw(DS1307__ADDRESS);
62 jlesech 157
    twi__send_data(DS1307__REG_SECONDS);
18 jlesech 158
 
159
    uint8_t seconds = ((p_time->seconds / 10) << 4) + (p_time->seconds % 10);
160
    uint8_t minutes = ((p_time->minutes / 10) << 4) + (p_time->minutes % 10);
161
    uint8_t hours = 0;
162
    if (DS1307__HOUR_MODE__12_HOUR == hour_mode)
163
    {
164
        hours = (hour_mode << 6) + (p_time->meridiem << 5)
165
            + ((p_time->hours / 10) << 4) + (p_time->hours % 10);
166
    }
167
    else
168
    {
169
        hours = (hour_mode << 6) + ((p_time->hours / 10) << 4)
170
            + (p_time->hours % 10);
171
    }
172
 
173
    twi__send_data(seconds);
174
    twi__send_data(minutes);
175
    twi__send_data(hours);
176
 
177
    twi__stop();
178
}
179
 
180
/**************************************************************************//**
181
 * \fn void ds1307__get_date(date_time__date_t* p_date)
182
 *
183
 * \brief Get RTC date.
184
 *
185
 * \param p_date a pointer to fill with RTC date
186
 ******************************************************************************/
187
void
188
ds1307__get_date
189
(
190
    datetime__date_t* p_date
191
){
192
    // Check the preconditions.
193
    assert(NULL != p_date);
194
 
195
    twi__start();
58 jlesech 196
    twi__send_slaw(DS1307__ADDRESS);
62 jlesech 197
    twi__send_data(DS1307__REG_DAY);
18 jlesech 198
    twi__stop();
199
 
200
    twi__start();
58 jlesech 201
    twi__send_slar(DS1307__ADDRESS);
18 jlesech 202
 
203
    uint8_t day = 0;
204
    twi__receive_data_ack(&day);
205
    uint8_t date = 0;
206
    twi__receive_data_ack(&date);
207
    uint8_t month = 0;
208
    twi__receive_data_ack(&month);
209
    uint8_t year = 0;
210
    twi__receive_data_nack(&year);
211
 
212
    p_date->day = day;
213
    p_date->date = (((date & 0x30) >> 4) * 10) + (date & 0x0F);
214
    p_date->month = (((month & 0x10) >> 4) * 10) + (month & 0x0F);
215
    p_date->year = (((year & 0xF0) >> 4) * 10) + (year & 0x0F);
216
 
217
    twi__stop();
218
}
219
 
220
/**************************************************************************//**
221
 * \fn void ds1307__set_date(date_time__date_t* p_date)
222
 *
223
 * \brief Set RTC date.
224
 *
225
 * \param p_date date to set
226
 ******************************************************************************/
227
void
228
ds1307__set_date
229
(
230
    datetime__date_t* p_date
231
){
232
    // Check the preconditions.
233
    assert(NULL != p_date);
234
 
235
    twi__start();
58 jlesech 236
    twi__send_slaw(DS1307__ADDRESS);
62 jlesech 237
    twi__send_data(DS1307__REG_DAY);
18 jlesech 238
 
239
    uint8_t date = ((p_date->date / 10) << 4) + (p_date->date % 10);
240
    uint8_t month = ((p_date->month / 10) << 4) + (p_date->month % 10);
241
    uint8_t year = ((p_date->year / 10) << 4) + (p_date->year % 10);
242
 
243
    twi__send_data(p_date->day);
244
    twi__send_data(date);
245
    twi__send_data(month);
246
    twi__send_data(year);
247
 
248
    twi__stop();
249
}
62 jlesech 250
 
251
/**************************************************************************//**
252
 * \fn void ds1307__set_square_wave_output_level(ds1307__sqw_out_level_t level)
253
 *
254
 * \brief Set square wave output pin level.
255
 *
256
 * \param level Level to set.
257
 ******************************************************************************/
258
void
259
ds1307__set_square_wave_output_level
260
(
261
    ds1307__sqw_out_level_t level
262
){
263
    twi__start();
264
    twi__send_slaw(DS1307__ADDRESS);
265
    twi__send_data(DS1307__REG_CONTROL);
266
    uint8_t register_value = (level == DS1307__SQW_LEVEL__LOW) ? 0x00 : 0x80;
267
    twi__send_data(register_value);
268
    twi__stop();
269
}
270
 
271
/**************************************************************************//**
272
 * \fn void ds1307__set_square_wave_output_signal(
273
 * ds1307__sqw_out__frequency_t    frequency,
274
 * bool                            enable)
275
 *
276
 * \brief Set Square-Wave output signal.
277
 *
278
 * \param   frequency   Frequency.
279
 * \param   enable      Status.
280
 ******************************************************************************/
281
void
282
ds1307__set_square_wave_output_signal
283
(
284
    ds1307__sqw_out__frequency_t    frequency,
285
    bool                            enable
286
){
287
    uint8_t register_value = 0;
288
 
289
    // Rate select.
290
    switch (frequency)
291
    {
292
        case DS1307__SQW_FREQUENCY__4096_HZ:
293
            register_value = _BV(DS1307__RS0);
294
            break;
295
 
296
        case DS1307__SQW_FREQUENCY__8192_HZ:
297
            register_value = _BV(DS1307__RS1);
298
            break;
299
 
300
        case DS1307__SQW_FREQUENCY__32768_HZ:
301
            register_value = _BV(DS1307__RS1) | _BV(DS1307__RS0);
302
            break;
303
 
304
        case DS1307__SQW_FREQUENCY__1_HZ:
305
        default:
306
            register_value = 0;
307
            break;
308
    }
309
 
310
    // Square-Wave enable.
311
    if (enable)
312
    {
313
        BIT__SET(register_value, DS1307__SQWE);
314
    }
315
 
316
    twi__start();
317
    twi__send_slaw(DS1307__ADDRESS);
318
    twi__send_data(DS1307__REG_CONTROL);
319
    twi__send_data(register_value);
320
    twi__stop();
321
}
63 jlesech 322
 
323
/**************************************************************************//**
324
 * \fn uint8_t ds1307__read_byte_in_ram(uint8_t address)
325
 *
326
 * \brief Read a byte in DS1307 RAM.
327
 *
328
 * \param address Address to read.
329
 *
330
 * \return Read byte.
331
 ******************************************************************************/
332
uint8_t
333
ds1307__read_byte_in_ram
334
(
335
    uint8_t address
336
){
337
    // Check the preconditions.
338
    assert(address >= 0x08);
339
    assert(address <= 0x3F);
340
 
341
    uint8_t data = 0;
342
 
343
    twi__start();
344
    twi__send_slaw(DS1307__ADDRESS);
345
    twi__send_data(address);
346
    twi__stop();
347
 
348
    twi__start();
349
    twi__send_slar(DS1307__ADDRESS);
350
    twi__receive_data_nack(&data);
351
    twi__stop();
352
 
353
    return data;
354
}
355
 
356
/**************************************************************************//**
357
 * \fn void ds1307__read_bytes_in_ram(
358
 * uint8_t  address,
359
 * uint8_t  length,
360
 * uint8_t* p_data)
361
 *
362
 * \brief Read bytes in DS1307 RAM.
363
 *
364
 * \param       address Address to read.
365
 * \param       length  Number of bytes to read.
366
 * \param[in]   p_data  Buffer to fill.
367
 ******************************************************************************/
368
void
369
ds1307__read_bytes_in_ram
370
(
371
    uint8_t     address,
372
    uint8_t     length,
373
    uint8_t*    p_data
374
){
375
    // Check the preconditions.
376
    assert(NULL != p_data);
377
    assert(address >= 0x08);
378
    assert(address <= 0x3F);
379
    assert(length <= 56);
380
 
381
    twi__start();
382
    twi__send_slaw(DS1307__ADDRESS);
383
    twi__send_data(address);
384
    twi__stop();
385
 
386
    twi__start();
387
    twi__send_slar(DS1307__ADDRESS);
388
    for (uint8_t i = 0; i < length - 1; i++)
389
    {
390
        twi__receive_data_ack(p_data + i);
391
    }
392
    twi__receive_data_nack(p_data + length - 1);
393
    twi__stop();
394
}
395
 
396
/**************************************************************************//**
397
 * \fn void ds1307__write_byte_in_ram(uint8_t address, uint8_t data)
398
 *
399
 * \brief Write a byte in DS1307 RAM.
400
 *
401
 * \param address   Address to write.
402
 * \param data      Byte to write.
403
 ******************************************************************************/
404
void
405
ds1307__write_byte_in_ram
406
(
407
    uint8_t address,
408
    uint8_t data
409
){
410
    // Check the preconditions.
411
    assert(address >= 0x08);
412
    assert(address <= 0x3F);
413
 
414
    twi__start();
415
    twi__send_slaw(DS1307__ADDRESS);
416
    twi__send_data(address);
417
    twi__send_data(data);
418
    twi__stop();
419
}
420
 
421
/**************************************************************************//**
422
 * \fn void ds1307__write_bytes_in_ram(uint8_t address, uint8_t data)
423
 *
424
 * \brief Write a byte in DS1307 RAM.
425
 *
426
 * \param       address Address to write.
427
 * \param       length  Number of bytes to write.
428
 * \param[in]   p_data  Bytes to write.
429
 ******************************************************************************/
430
void
431
ds1307__write_bytes_in_ram
432
(
433
    uint8_t     address,
434
    uint8_t     length,
435
    uint8_t*    p_data
436
){
437
    // Check the preconditions.
438
    assert(NULL != p_data);
439
    assert(address >= 0x08);
440
    assert(address <= 0x3F);
441
    assert(length <= 56);
442
 
443
    twi__start();
444
    twi__send_slaw(DS1307__ADDRESS);
445
    twi__send_data(address);
446
    for (uint8_t i = 0; i < length; i++)
447
    {
448
        twi__send_data(p_data[i]);
449
    }
450
    twi__stop();
451
}