Skip to content

Commit 5cb0be3

Browse files
authored
Merge pull request #7312 from miri64/ds1307/feat/initial
ds1307: initial import of a driver for the DS1307 RTC
2 parents 03caac8 + 94763ab commit 5cb0be3

File tree

11 files changed

+709
-0
lines changed

11 files changed

+709
-0
lines changed

drivers/Makefile.dep

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ ifneq (,$(filter dht,$(USEMODULE)))
8484
FEATURES_REQUIRED += periph_gpio
8585
endif
8686

87+
ifneq (,$(filter ds1307,$(USEMODULE)))
88+
FEATURES_REQUIRED += periph_i2c
89+
endif
90+
8791
ifneq (,$(filter dsp0401,$(USEMODULE)))
8892
USEMODULE += xtimer
8993
FEATURES_REQUIRED += periph_gpio

drivers/Makefile.include

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ endif
1010
ifneq (,$(filter cc110x,$(USEMODULE)))
1111
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc110x/include
1212
endif
13+
ifneq (,$(filter ds1307,$(USEMODULE)))
14+
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds1307/include
15+
endif
1316
ifneq (,$(filter kw2xrf,$(USEMODULE)))
1417
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/kw2xrf/include
1518
endif

drivers/ds1307/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include $(RIOTBASE)/Makefile.base

drivers/ds1307/ds1307.c

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright (C) 2017 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @{
11+
*
12+
* @file
13+
* @author Martine Lenders <m.lenders@fu-berlin.de>
14+
*/
15+
16+
#include <string.h>
17+
18+
#include "bcd.h"
19+
20+
#include "ds1307.h"
21+
#include "ds1307_internal.h"
22+
23+
#define ENABLE_DEBUG (0)
24+
#include "debug.h"
25+
26+
static int _nvram_read(struct nvram *dev, uint8_t *dst, uint32_t src,
27+
size_t size);
28+
static int _nvram_write(struct nvram *dev, const uint8_t *src, uint32_t dst,
29+
size_t size);
30+
31+
static uint8_t _convert_12_to_24(uint8_t hour)
32+
{
33+
if (hour & DS1307_REG_HOUR_12H) {
34+
uint8_t tmp = bcd_to_byte(hour & DS1307_REG_HOUR_12H_MASK);
35+
if (hour & DS1307_REG_HOUR_PM) {
36+
if (tmp < 12) {
37+
tmp += 12;
38+
}
39+
}
40+
else {
41+
if (tmp == 12) {
42+
tmp = 0;
43+
}
44+
}
45+
hour = (bcd_from_byte(tmp) & DS1307_REG_HOUR_24H_MASK);
46+
}
47+
return hour;
48+
}
49+
50+
int ds1307_init(ds1307_t *dev, const ds1307_params_t *params)
51+
{
52+
int res;
53+
uint8_t hour;
54+
55+
dev->i2c = params->i2c;
56+
57+
i2c_acquire(dev->i2c);
58+
res = i2c_init_master(dev->i2c, params->clk);
59+
if (res < 0) {
60+
i2c_release(dev->i2c);
61+
DEBUG("ds1307: Error initializing I2C: %i\n", res);
62+
return -1;
63+
}
64+
/* normalize hour format */
65+
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_HOUR, &hour);
66+
if (res < 0) {
67+
i2c_release(dev->i2c);
68+
DEBUG("ds1307: Error reading HOUR register on init: %i\n", res);
69+
return -1;
70+
}
71+
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_HOUR,
72+
_convert_12_to_24(hour));
73+
i2c_release(dev->i2c);
74+
75+
if (res < 0) {
76+
DEBUG("ds1307: Error writing HOUR register on init: %i\n", res);
77+
return -1;
78+
}
79+
dev->nvram.read = _nvram_read;
80+
dev->nvram.write = _nvram_write;
81+
dev->nvram.size = (DS1307_REG_RAM_LAST - DS1307_REG_RAM_FIRST) + 1;
82+
dev->nvram.extra = dev;
83+
return 0;
84+
}
85+
86+
int ds1307_set_time(const ds1307_t *dev, const struct tm *time)
87+
{
88+
uint8_t regs[DS1307_REG_YEAR - DS1307_REG_SEC + 1];
89+
int res;
90+
91+
regs[DS1307_REG_SEC] = (bcd_from_byte(time->tm_sec) & DS1307_REG_SEC_MASK);
92+
regs[DS1307_REG_MIN] = (bcd_from_byte(time->tm_min) & DS1307_REG_MIN_MASK);
93+
regs[DS1307_REG_HOUR] = (bcd_from_byte(time->tm_hour) &
94+
DS1307_REG_HOUR_24H_MASK);
95+
regs[DS1307_REG_DOW] = (bcd_from_byte(time->tm_wday + DS1307_DOW_OFFSET) &
96+
DS1307_REG_DOW_MASK);
97+
regs[DS1307_REG_DOM] = (bcd_from_byte(time->tm_mday) & DS1307_REG_DOM_MASK);
98+
regs[DS1307_REG_MON] = (bcd_from_byte(time->tm_mon + DS1307_MON_OFFSET) &
99+
DS1307_REG_MON_MASK);
100+
regs[DS1307_REG_YEAR] = bcd_from_byte(time->tm_year + DS1307_YEAR_OFFSET);
101+
i2c_acquire(dev->i2c);
102+
res = i2c_write_regs(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, regs,
103+
sizeof(regs));
104+
DEBUG("ds1307: wrote bytes %02x %02x %02x %02x %02x %02x %02x to device (result: %i)\n",
105+
regs[DS1307_REG_SEC], regs[DS1307_REG_MIN], regs[DS1307_REG_HOUR],
106+
regs[DS1307_REG_DOW], regs[DS1307_REG_DOM], regs[DS1307_REG_MON],
107+
regs[DS1307_REG_YEAR], res);
108+
i2c_release(dev->i2c);
109+
return (res < 0) ? -1 : 0;
110+
}
111+
112+
int ds1307_get_time(const ds1307_t *dev, struct tm *time)
113+
{
114+
uint8_t regs[DS1307_REG_YEAR - DS1307_REG_SEC + 1];
115+
int res;
116+
117+
i2c_acquire(dev->i2c);
118+
res = i2c_read_regs(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, regs,
119+
sizeof(regs));
120+
DEBUG("ds1307: read bytes %02x %02x %02x %02x %02x %02x %02x from device (result: %i)\n",
121+
regs[DS1307_REG_SEC], regs[DS1307_REG_MIN], regs[DS1307_REG_HOUR],
122+
regs[DS1307_REG_DOW], regs[DS1307_REG_DOM], regs[DS1307_REG_MON],
123+
regs[DS1307_REG_YEAR], res);
124+
i2c_release(dev->i2c);
125+
if (res < 0) {
126+
return -1;
127+
}
128+
time->tm_sec = bcd_to_byte(regs[DS1307_REG_SEC] & DS1307_REG_SEC_MASK);
129+
time->tm_min = bcd_to_byte(regs[DS1307_REG_MIN] & DS1307_REG_MIN_MASK);
130+
time->tm_hour = bcd_to_byte(regs[DS1307_REG_HOUR] &
131+
DS1307_REG_HOUR_24H_MASK);
132+
time->tm_wday = (bcd_to_byte(regs[DS1307_REG_DOW] & DS1307_REG_DOW_MASK) -
133+
DS1307_DOW_OFFSET);
134+
time->tm_mday = bcd_to_byte(regs[DS1307_REG_DOM] & DS1307_REG_DOM_MASK);
135+
time->tm_mon = bcd_to_byte(regs[DS1307_REG_MON] & DS1307_REG_MON_MASK) -
136+
DS1307_MON_OFFSET;
137+
time->tm_year = (bcd_to_byte(regs[DS1307_REG_YEAR]) - DS1307_YEAR_OFFSET);
138+
return 0;
139+
}
140+
141+
int ds1307_halt(const ds1307_t *dev)
142+
{
143+
int res;
144+
uint8_t sec;
145+
146+
i2c_acquire(dev->i2c);
147+
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, &sec);
148+
if (res < 0) {
149+
i2c_release(dev->i2c);
150+
DEBUG("ds1307: Error reading SEC register on halt: %i\n", res);
151+
return -1;
152+
}
153+
sec |= DS1307_REG_SEC_CH;
154+
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, sec);
155+
i2c_release(dev->i2c);
156+
return (res < 0) ? -1 : 0;
157+
}
158+
159+
int ds1307_set_sqw_mode(const ds1307_t *dev, ds1307_sqw_mode_t mode)
160+
{
161+
int res;
162+
163+
i2c_acquire(dev->i2c);
164+
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SQW_CTL,
165+
(uint8_t)mode);
166+
i2c_release(dev->i2c);
167+
return res;
168+
}
169+
170+
int ds1307_get_sqw_mode(const ds1307_t *dev)
171+
{
172+
uint8_t mode;
173+
int res;
174+
175+
i2c_acquire(dev->i2c);
176+
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SQW_CTL, &mode);
177+
i2c_release(dev->i2c);
178+
return (res < 0) ? res : (int)mode;
179+
}
180+
181+
static int _nvram_read(struct nvram *nvram, uint8_t *dst, uint32_t src,
182+
size_t size)
183+
{
184+
const ds1307_t *dev = nvram->extra;
185+
int res;
186+
187+
if ((src + size) > nvram->size) {
188+
return -3;
189+
}
190+
i2c_acquire(dev->i2c);
191+
res = i2c_read_regs(dev->i2c, DS1307_I2C_ADDRESS,
192+
DS1307_REG_RAM_FIRST + src, dst, size);
193+
i2c_release(dev->i2c);
194+
return res;
195+
}
196+
197+
static int _nvram_write(struct nvram *nvram, const uint8_t *src, uint32_t dst,
198+
size_t size)
199+
{
200+
const ds1307_t *dev = nvram->extra;
201+
int res;
202+
203+
if ((dst + size) > nvram->size) {
204+
return -3;
205+
}
206+
i2c_acquire(dev->i2c);
207+
res = i2c_write_regs(dev->i2c, DS1307_I2C_ADDRESS,
208+
DS1307_REG_RAM_FIRST + dst, src, size);
209+
i2c_release(dev->i2c);
210+
return res;
211+
}
212+
213+
/** @} */
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (C) 2017 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @ingroup drivers_ds1307
11+
* @brief
12+
* @{
13+
*
14+
* @file
15+
* @brief Register definitions for DS1307 RTC
16+
*
17+
* @author Martine Lenders <m.lenders@fu-berlin.de>
18+
*/
19+
#ifndef DS1307_INTERNAL_H
20+
#define DS1307_INTERNAL_H
21+
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
26+
/**
27+
* @name Registers
28+
* @{
29+
*/
30+
#define DS1307_REG_SEC (0x00) /**< seconds */
31+
#define DS1307_REG_MIN (0x01) /**< minutes */
32+
#define DS1307_REG_HOUR (0x02) /**< hours */
33+
#define DS1307_REG_DOW (0x03) /**< day of week (1-7, 1 == sunday) */
34+
#define DS1307_REG_DOM (0x04) /**< day of month */
35+
#define DS1307_REG_MON (0x05) /**< month */
36+
#define DS1307_REG_YEAR (0x06) /**< year */
37+
#define DS1307_REG_SQW_CTL (0x07) /**< SQW control */
38+
#define DS1307_REG_RAM_FIRST (0x08) /**< NVRAM start */
39+
#define DS1307_REG_RAM_LAST (0x3F) /**< NVRAM end */
40+
/** @} */
41+
42+
/**
43+
* @name Register bits
44+
* @{
45+
*/
46+
#define DS1307_REG_SEC_CH (0x80) /**< clock halt bit */
47+
#define DS1307_REG_SEC_MASK (0x7f) /**< seconds mask */
48+
#define DS1307_REG_MIN_MASK (0x7f) /**< minutes mask */
49+
#define DS1307_REG_HOUR_12H (0x40) /**< 12-hour (0) / 24-hour (1) mode */
50+
#define DS1307_REG_HOUR_PM (0x20) /**< AM (0) / PM (1) in 12-hour mode */
51+
#define DS1307_REG_HOUR_12H_MASK (0x2f) /**< hour (12-hour mode) */
52+
#define DS1307_REG_HOUR_24H_MASK (0x3f) /**< hour (24-hour mode) */
53+
#define DS1307_REG_DOW_MASK (0x07) /**< day of week mask */
54+
#define DS1307_REG_DOM_MASK (0x3f) /**< day of month mask */
55+
#define DS1307_REG_MON_MASK (0x1f) /**< month mask */
56+
/** @} */
57+
58+
/**
59+
* @name Custom offsets (to DS1307 registers to struct tm)
60+
* @{
61+
*/
62+
#define DS1307_DOW_OFFSET (1) /**< offset in days from sunday */
63+
#define DS1307_MON_OFFSET (1) /**< offset in month from January */
64+
#define DS1307_YEAR_OFFSET (-100) /**< offset in years from 1900 */
65+
/** @} */
66+
67+
68+
#ifdef __cplusplus
69+
}
70+
#endif
71+
72+
#endif /* DS1307_INTERNAL_H */
73+
/** @} */
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (C) 2017 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @ingroup drivers_ds1307
11+
* @{
12+
*
13+
* @file
14+
* @brief Default configuration for DS1307 devices
15+
*
16+
* @author Martine Lenders <m.lenders@fu-berlin.de>
17+
*/
18+
#ifndef DS1307_PARAMS_H
19+
#define DS1307_PARAMS_H
20+
21+
#include "board.h"
22+
#include "ds1307.h"
23+
24+
#ifdef __cplusplus
25+
extern "C" {
26+
#endif
27+
28+
/**
29+
* @name Default configuration parameters for the DS1307 driver
30+
* @{
31+
*/
32+
#ifndef DS1307_PARAM_I2C
33+
#define DS1307_PARAM_I2C (I2C_DEV(0))
34+
#endif
35+
#ifndef DS1307_PARAM_I2C_CLK
36+
#define DS1307_PARAM_I2C_CLK (DS1307_I2C_MAX_CLK)
37+
38+
#define DS1307_PARAMS_DEFAULT { .i2c = DS1307_PARAM_I2C, \
39+
.clk = DS1307_PARAM_I2C_CLK }
40+
41+
#endif
42+
/** @} */
43+
44+
/**
45+
* @brief DS1307 configuration
46+
*/
47+
static const ds1307_params_t ds1307_params[] =
48+
{
49+
#ifdef DS1307_PARAMS_BOARD
50+
DS1307_PARAMS_BOARD,
51+
#else
52+
DS1307_PARAMS_DEFAULT,
53+
#endif
54+
};
55+
56+
#ifdef __cplusplus
57+
}
58+
#endif
59+
60+
#endif /* DS1307_PARAMS_H */
61+
/** @} */

0 commit comments

Comments
 (0)