Contiki 3.x
ds3231-sensor.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Timothy Rule <trule.github@nym.hush.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /**
31  * @file
32  * Sensors for DS3231 (RTC with Temperature Sensor).
33  * @author
34  * Timothy Rule <trule.github@nym.hush.com>
35  * @note
36  * See http://www.maxim-ic.com/datasheet/index.mvp/id/4627
37  */
38 
39 #include "ds3231-sensor.h"
40 #include <stdio.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <contiki.h>
44 #include "i2c.h"
45 #include <inttypes.h>
46 
47 //#define DEBUG
48 #ifdef DEBUG
49 #define dprintf(FORMAT, args...) printf(FORMAT, ##args)
50 #else
51 #define dprintf(...)
52 #endif
53 
54 /**
55  * DS3231 is connected to TWI Master on Port C (Pins 0 & 1). The active low
56  * Interrupt from the DS3231 is connected in Pin 2 of Port C.
57  */
58 //#define I2C(a,b,c,d) twi_transaction(&TWIC, DS3231_ADDR, (a), (b), (c), (d));
59 
60 int I2C(uint8_t* write,uint16_t write_len,uint8_t* read,uint16_t read_len)
61 {
62  // This gets disabled (not be us) sometimes
64 
65  uint8_t write_res = I2C_MASTER_ERR_NONE;
66  uint8_t read_res = I2C_MASTER_ERR_NONE;
67 
68  if (write_len) {
69  write_res = i2c_burst_send(DS3231_ADDR, write, write_len);
70  }
71 
72  if (read_len) {
73  read_res = i2c_burst_receive(DS3231_ADDR, read, read_len);
74  }
75 
77 
78  // 0 for success
79  return !(write_res == I2C_MASTER_ERR_NONE && read_res == I2C_MASTER_ERR_NONE);
80 }
81 
82 /* Define the sensor object. */
83 const struct sensors_sensor ds3231_sensor;
84 
85 /* Sensor status. */
86 enum {
87  ON,
88  OFF
89 };
90 static uint8_t state = OFF;
91 
92 /**
93  * ds3231_get_time
94  *
95  * @return 0 for success, I2C error code otherwise.
96  *
97  * @note The base date of tm struct is 1900-01-01 and the base date stored
98  * in the RTC for this application is 2000-01-01. An adjustment of
99  * 100 is made before getting the time.
100  */
101 int ds3231_get_time(struct tm *t) {
102  int rc;
103  ds_3231_time_t time;
104 
105  memset(time.data, 0, 8);
106 
107  /* Read the time from the DS3231. */
108  time.tm.address = 0;
109  rc = I2C(time.data, 1, &time.data[1], 7);
110  if (rc != 0) {
111  return rc;
112  }
113 
114  /* Convert to tm struct */
115  t->tm_year = time.tm.year + time.tm.dyear * 10 + 100;
116  // Month field should be 0 indexed.
117  t->tm_mon = time.tm.mon + time.tm.dmon * 10 -1;
118  t->tm_mday = time.tm.date + time.tm.ddate * 10;
119  t->tm_hour = time.tm.hour + time.tm.dhour * 10;
120  t->tm_min = time.tm.min + time.tm.dmin * 10;
121  t->tm_sec = time.tm.sec + time.tm.dsec * 10;
122 
123  dprintf("years %d, months %d, days %d, hours %d, minutes %d, seconds %d\n", t->tm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
124 
125  return 0;
126 }
127 
128 /**
129  * ds3231_set_time
130  *
131  * @return 0 for success, I2C error code otherwise.
132  *
133  * @note The base date of tm struct is 1900-01-01 and the base date stored
134  * in the RTC for this application is 2000-01-01. An adjustment of
135  * 100 is made before setting the time.
136  */
137 int ds3231_set_time(struct tm *t) {
138  int rc;
139  ds_3231_time_t time;
140 
141  memset(time.data, 0, 8);
142 
143  /* Convert the tm struct to the register representation of the DS3231. */
144  time.tm.dyear = (t->tm_year - 100) / 10;
145  time.tm.year = (t->tm_year - 100) % 10;
146  // Months in struct tm are 0 indexed
147  time.tm.dmon = (t->tm_mon + 1) / 10;
148  time.tm.mon = (t->tm_mon + 1) % 10;
149  time.tm.ddate = t->tm_mday / 10;
150  time.tm.date = t->tm_mday % 10;
151  time.tm.day = 1; /* Not used, set to 1. */
152  time.tm.dhour = t->tm_hour / 10;
153  time.tm.hour = t->tm_hour % 10;
154  time.tm.dmin = t->tm_min / 10;
155  time.tm.min = t->tm_min % 10;
156  time.tm.dsec = t->tm_sec / 10;
157  time.tm.sec = t->tm_sec % 10;
158 
159  dprintf("year %d%d, months %d%d, days %d%d, hours %d%d, minutes %d%d, seconds %d%d\n", time.tm.dyear, time.tm.year, time.tm.dmon, time.tm.mon, time.tm.ddate, time.tm.date, time.tm.dhour, time.tm.hour, time.tm.dmin, time.tm.min, time.tm.dsec, time.tm.sec);
160  /* Send the new time to the DS3231. */
161  rc = I2C(time.data, 8, NULL, 0);
162  if (rc != 0) {
163  return rc;
164  }
165 
166  return 0;
167 }
168 
169 /**
170  * ds3231_set_alarm
171  *
172  * Sets the first alarm of the DS3231. Alarm Mask Bits A1M1-4 are all set
173  * to 0 which means the alarm will fire on the complete alarm setting (date,
174  * hour, minute & second).
175  *
176  * When the alarm is triggered the INT pin of the DS3231 will be pulled low.
177  * This pin is connected to Port C Pin 2 of the AVR XMega.
178  *
179  * @return 0 for success, I2C error code otherwise.
180  */
181 int ds3231_set_alarm(struct tm *t)
182 {
183  int rc;
184  ds_3231_alarm_t alarm;
185  uint8_t regs[3];
186 
187  memset(alarm.data, 0, 5);
188 
189  /* Set the Alarm 1 registers. */
190  alarm.tm.address = 7; /* DS3231 register 7, start of Alarm 1. */
191  alarm.tm.ddate = t->tm_mday / 10;
192  alarm.tm.date = t->tm_mday % 10;
193  alarm.tm.dhour = t->tm_hour / 10;
194  alarm.tm.hour = t->tm_hour % 10;
195  alarm.tm.dmin = t->tm_min / 10;
196  alarm.tm.min = t->tm_min % 10;
197  alarm.tm.dsec = t->tm_sec / 10;
198  alarm.tm.sec = t->tm_sec % 10;
199 
200  /* Send the Alarm to the DS3231. */
201  rc = I2C(alarm.data, 5, NULL, 0);
202  if (rc != 0) {
203  return rc;
204  }
205 
206  /* Read in Control and Status registers. */
207  regs[0] = 0x0e;
208  rc = I2C(&regs[0], 1, &regs[1], 2);
209  if (rc != 0) {
210  return rc;
211  }
212 
213  /* Enable Alarm 1, then write the Control and Status registers. */
214  regs[1] |= DS3231_CONTROL_A1IE_SET_MASK;
215  regs[2] &= DS3231_STATUS_A1F_CLEAR_MASK;
216  rc = I2C(regs, 3, NULL, 0);
217  if (rc != 0) {
218  return rc;
219  }
220 
221  return 0;
222 }
223 
224 /**
225  * ds3231_clear_alarm
226  *
227  * Clears and disables Alarm 1.
228  *
229  * @return 0 for success, I2C error code otherwise.
230  */
232 {
233  int rc;
234  uint8_t regs[3];
235 
236  /* Read in Control and Status registers. */
237  regs[0] = 0x0e;
238  rc = I2C(&regs[0], 1, &regs[1], 2);
239  if (rc != 0) {
240  return rc;
241  }
242 
243  /* Write the Control and Status registers. */
244  regs[1] &= DS3231_CONTROL_A1IE_CLEAR_MASK;
245  regs[2] &= DS3231_STATUS_A1F_CLEAR_MASK;
246  rc = I2C(regs, 3, NULL, 0);
247  if (rc != 0) {
248  return rc;
249  }
250 
251  return 0;
252 }
253 
254 /**
255  * ds3231_temperature
256  *
257  * Register 11h: bit 7 is sign, bit 6-0 are temperature.
258  * Register 12h: bit 7 & 6 are decimal point (0.25 * xxb).
259  *
260  * @return Temperature * 100 (centi %) however accuracy is limited to
261  * 0.25 degree increments.
262  */
263 int ds3231_get_temperature(int *temperature)
264 {
265  int rc;
266  uint8_t addr_set[6] = { 0x11 };
267  uint8_t temp_regs[21];
268 
269  rc = I2C(addr_set, 1, temp_regs, 2);
270  if (rc != 0) {
271  return rc;
272  }
273 
274  *temperature = ((temp_regs[0]) & 0x7f) * 100; /* Temperature in cC. */
275  *temperature += ((temp_regs[1] & 0xc0) >> 6) * 25; /* .25 .. .75 */
276  if (temp_regs[0] & 0x80)
277  *temperature *= -1;
278 
279  dprintf("Temperature is %d\n", *temperature);
280 
281  return 0;
282 }
283 
284 /**
285  * configure
286  */
287 int configure(int type, int c)
288 {
289  int rc = 0;
290 
291  switch (type) {
292  case DS3231_CONFIG_SET_TIME:
293  /* The address of a tm structure is pass via variable
294  * 'c' which works because sizeof(tm*) and sizeof(int)
295  * are the same on AVR XMEGA. Its generally not a good
296  * thing to do ... things like that. */
297  return ds3231_set_time((struct tm*) c);
298  case DS3231_CONFIG_SET_ALARM:
299  return ds3231_set_alarm((struct tm*) c);
300  case DS3231_CONFIG_CLEAR_ALARM:
301  return ds3231_clear_alarm();
302  case SENSORS_ACTIVE:
303  if (c) {
304  state = OFF;
305  dprintf("DS3231 Sensor Configure ...\n");
306  rc = ds3231_clear_alarm();
307  if (rc == 0)
308  state = ON;
309  break;
310  }
311  default:
312  state = OFF;
313  }
314 
315  return 0;
316 }
317 
318 /**
319  * status
320  */
321 int status(int type)
322 {
323  switch (type) {
324  case SENSORS_ACTIVE:
325  case SENSORS_READY:
326  return (state == ON);
327  default:
328  return 0;
329  }
330 }
331 
332 /* Initialise the sensor object and make it available to Contiki OS. */
333 SENSORS_SENSOR(ds3231_sensor, "ds3231", NULL, configure, status);
Sensors for DS3231 (RTC with Temperature Sensor).
void i2c_master_disable(void)
Disable master I2C module.
Definition: i2c.c:97
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91
int I2C(uint8_t *write, uint16_t write_len, uint8_t *read, uint16_t read_len)
DS3231 is connected to TWI Master on Port C (Pins 0 & 1).
Definition: ds3231-sensor.c:62
int ds3231_set_alarm(struct tm *t)
ds3231_set_alarm
const struct sensors_sensor ds3231_sensor
Export the DS3231 sensor object.
Definition: ds3231-sensor.c:82
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
#define NULL
The null pointer.
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
int ds3231_get_time(struct tm *t)
ds3231_get_time
int configure(int type, int c)
configure
int ds3231_clear_alarm(void)
ds3231_clear_alarm
int ds3231_set_time(struct tm *t)
ds3231_set_time
tm
Definition: utc_time.h:20
int ds3231_get_temperature(int *temperature)
ds3231_temperature
int status(int type)
status