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 <stdlib.h>
40 #include <stdio.h>
41 #include <stddef.h>
42 #include <stdint.h>
43 #include <string.h>
44 #include <contiki.h>
45 #include "ds3231-sensor.h"
46 #include "i2cmaster.h"
47 #include <inttypes.h>
48 
49 //#define DEBUG
50 #ifdef DEBUG
51 #define dprintf(FORMAT, args...) printf_P(PSTR(FORMAT), ##args)
52 #else
53 #define dprintf(...)
54 #endif
55 
56 /**
57  * DS3231 is connected to TWI Master on Port C (Pins 0 & 1). The active low
58  * Interrupt from the DS3231 is connected in Pin 2 of Port C.
59  */
60 //#define I2C(a,b,c,d) twi_transaction(&TWIC, DS3231_ADDR, (a), (b), (c), (d));
61 
62 int I2C(uint8_t* write,uint16_t write_len,uint8_t* read,uint16_t read_len)
63 {
64  if (write_len) {
65  i2c_transmitinit(DS3231_ADDR);
66  while(i2c_busy());
67  i2c_transmit_n(write_len,write);
68  while(i2c_busy());
69  }
70 
71  if (read_len) {
72  i2c_receiveinit(DS3231_ADDR);
73  while(i2c_busy());
74  i2c_receive_n(read_len,read);
75  while(i2c_busy());
76  }
77 
78  return(0);
79 }
80 
81 /* Define the sensor object. */
82 const struct sensors_sensor ds3231_sensor;
83 
84 /* Sensor status. */
85 enum {
86  ON,
87  OFF
88 };
89 static uint8_t state = OFF;
90 
91 /**
92  * ds3231_get_time
93  *
94  * @return 0 for success, -ve for error.
95  *
96  * @note The base date of tm struct is 1900-01-01 and the base date stored
97  * in the RTC for this application is 2000-01-01. An adjustment of
98  * 100 is made before getting the time.
99  */
100 int ds3231_get_time(struct tm *t) {
101  int rc;
102  ds_3231_time_t time;
103 
104  memset(time.data, 0, 8);
105 
106  /* Read the time from the DS3231. */
107  time.tm.address = 0;
108  rc = I2C(time.data, 1, &time.data[1], 7);
109  if (rc != 0) {
110  return rc;
111  }
112 
113  /* Convert to tm struct */
114  t->tm_year = time.tm.year + time.tm.dyear * 10 + 100;
115  // Month field should be 0 indexed.
116  t->tm_mon = time.tm.mon + time.tm.dmon * 10 -1;
117  t->tm_mday = time.tm.date + time.tm.ddate * 10;
118  t->tm_hour = time.tm.hour + time.tm.dhour * 10;
119  t->tm_min = time.tm.min + time.tm.dmin * 10;
120  t->tm_sec = time.tm.sec + time.tm.dsec * 10;
121 
122  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);
123 
124  return 0;
125 }
126 
127 /**
128  * ds3231_set_time
129  *
130  * @return 0 for success, -ve for error.
131  *
132  * @note The base date of tm struct is 1900-01-01 and the base date stored
133  * in the RTC for this application is 2000-01-01. An adjustment of
134  * 100 is made before setting the time.
135  */
136 int ds3231_set_time(struct tm *t) {
137  int rc;
138  ds_3231_time_t time;
139 
140  memset(time.data, 0, 8);
141 
142  /* Convert the tm struct to the register representation of the DS3231. */
143  time.tm.dyear = (t->tm_year - 100) / 10;
144  time.tm.year = (t->tm_year - 100) % 10;
145  // Months in struct tm are 0 indexed
146  time.tm.dmon = (t->tm_mon + 1) / 10;
147  time.tm.mon = (t->tm_mon + 1) % 10;
148  time.tm.ddate = t->tm_mday / 10;
149  time.tm.date = t->tm_mday % 10;
150  time.tm.day = 1; /* Not used, set to 1. */
151  time.tm.dhour = t->tm_hour / 10;
152  time.tm.hour = t->tm_hour % 10;
153  time.tm.dmin = t->tm_min / 10;
154  time.tm.min = t->tm_min % 10;
155  time.tm.dsec = t->tm_sec / 10;
156  time.tm.sec = t->tm_sec % 10;
157 
158  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);
159  /* Send the new time to the DS3231. */
160  rc = I2C(time.data, 8, NULL, 0);
161  if (rc != 0) {
162  return rc;
163  }
164 
165  return 0;
166 }
167 
168 /**
169  * ds3231_set_alarm
170  *
171  * Sets the first alarm of the DS3231. Alarm Mask Bits A1M1-4 are all set
172  * to 0 which means the alarm will fire on the complete alarm setting (date,
173  * hour, minute & second).
174  *
175  * When the alarm is triggered the INT pin of the DS3231 will be pulled low.
176  * This pin is connected to Port C Pin 2 of the AVR XMega.
177  *
178  * @return 0 for success, -ve for error.
179  */
180 int ds3231_set_alarm(struct tm *t)
181 {
182  int rc;
183  ds_3231_alarm_t alarm;
184  uint8_t regs[3];
185 
186  memset(alarm.data, 0, 5);
187 
188  /* Set the Alarm 1 registers. */
189  alarm.tm.address = 7; /* DS3231 register 7, start of Alarm 1. */
190  alarm.tm.ddate = t->tm_mday / 10;
191  alarm.tm.date = t->tm_mday % 10;
192  alarm.tm.dhour = t->tm_hour / 10;
193  alarm.tm.hour = t->tm_hour % 10;
194  alarm.tm.dmin = t->tm_min / 10;
195  alarm.tm.min = t->tm_min % 10;
196  alarm.tm.dsec = t->tm_sec / 10;
197  alarm.tm.sec = t->tm_sec % 10;
198 
199  /* Send the Alarm to the DS3231. */
200  rc = I2C(alarm.data, 5, NULL, 0);
201  if (rc != 0) {
202  return rc;
203  }
204 
205  /* Read in Control and Status registers. */
206  regs[0] = 0x0e;
207  rc = I2C(&regs[0], 1, &regs[1], 2);
208  if (rc != 0) {
209  return rc;
210  }
211 
212  /* Enable Alarm 1, then write the Control and Status registers. */
213  regs[1] |= DS3231_CONTROL_A1IE_SET_MASK;
214  regs[2] &= DS3231_STATUS_A1F_CLEAR_MASK;
215  rc = I2C(regs, 3, NULL, 0);
216  if (rc != 0) {
217  return rc;
218  }
219 
220  return 0;
221 }
222 
223 /**
224  * ds3231_clear_alarm
225  *
226  * Clears and disables Alarm 1.
227  *
228  * @return 0 for success, -ve for error.
229  */
231 {
232  int rc;
233  uint8_t regs[3];
234 
235  /* Read in Control and Status registers. */
236  regs[0] = 0x0e;
237  rc = I2C(&regs[0], 1, &regs[1], 2);
238  if (rc != 0) {
239  return rc;
240  }
241 
242  /* Write the Control and Status registers. */
243  regs[1] &= DS3231_CONTROL_A1IE_CLEAR_MASK;
244  regs[2] &= DS3231_STATUS_A1F_CLEAR_MASK;
245  rc = I2C(regs, 3, NULL, 0);
246  if (rc != 0) {
247  return rc;
248  }
249 
250  return 0;
251 }
252 
253 /**
254  * ds3231_temperature
255  *
256  * Register 11h: bit 7 is sign, bit 6-0 are temperature.
257  * Register 12h: bit 7 & 6 are decimal point (0.25 * xxb).
258  *
259  * @return Temperature * 100 (centi %) however accuracy is limited to
260  * 0.25 degree increments.
261  */
263 {
264  int rc;
265  uint8_t addr_set[6] = { 0x11 };
266  uint8_t temp_regs[21];
267  int temperature;
268 
269  rc = I2C(addr_set, 1, temp_regs, 2);
270  if (rc != 0) {
271  return 0;
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 temperature;
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((tm*) c);
298  case DS3231_CONFIG_SET_ALARM:
299  return ds3231_set_alarm((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);
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
I2C communication device driver header file for Zolertia Z1 sensor node.
int ds3231_set_alarm(struct tm *t)
ds3231_set_alarm
Sensors for DS3231 (RTC with Temperature Sensor).
const struct sensors_sensor ds3231_sensor
Export the DS3231 sensor object.
Definition: ds3231-sensor.c:82
#define NULL
The null pointer.
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
int ds3231_temperature(void)
ds3231_temperature
tm
Definition: utc_time.h:20
int status(int type)
status