Contiki-NG
Loading...
Searching...
No Matches
rtcc.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Zolertia <http://www.zolertia.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 * This file is part of the Contiki operating system.
30 *
31 */
32/*---------------------------------------------------------------------------*/
33/**
34 * \addtogroup remote-rtcc
35 * @{
36 *
37 * Driver for the RE-Mote RTCC (Real Time Clock Calendar)
38 * @{
39 *
40 * \file
41 * Driver for the RE-Mote RF Real Time Clock Calendar (RTCC)
42 *
43 * \author
44 *
45 * Antonio Lignan <alinan@zolertia.com>
46 * Aitor Mejias <amejias@zolertia.com>
47 * Toni Lozano <tlozano@zolertia.com>
48 */
49/*---------------------------------------------------------------------------*/
50#include "contiki.h"
51#include "dev/gpio.h"
52#include "dev/i2c.h"
53#include "rtcc.h"
54#include "rtcc-config.h"
55#include "dev/leds.h"
56#include <stdio.h>
57/*---------------------------------------------------------------------------*/
58#define DEBUG 0
59#if DEBUG
60#define PRINTF(...) printf(__VA_ARGS__)
61#else
62#define PRINTF(...)
63#endif
64/*---------------------------------------------------------------------------*/
65#define RTC_INT1_PORT_BASE GPIO_PORT_TO_BASE(RTC_INT1_PORT)
66#define RTC_INT1_PIN_MASK GPIO_PIN_MASK(RTC_INT1_PIN)
67/*---------------------------------------------------------------------------*/
68/* Callback pointers when interrupt occurs */
69void (*rtcc_int1_callback)(uint8_t value);
70/* -------------------------------------------------------------------------- */
71static const char *ab080x_td_register_name[] =
72{
73 "Mseconds",
74 "Seconds",
75 "Minutes",
76 "Hours",
77 "Days",
78 "Months",
79 "Years",
80 "Weekdays",
81};
82/* -------------------------------------------------------------------------- */
83static const char *ab080x_config_register_name[] =
84{
85 "STATUS",
86 "CTRL1",
87 "CTRL2",
88 "INTMASK",
89 "SQW",
90 "CAL_XT",
91 "CAL_RCU",
92 "CAL_RCL",
93 "INTPOL",
94 "TIMER_CTRL",
95 "TIMER_CDOWN",
96 "TIMER_INIT",
97 "WDT",
98 "OSC_CTRL",
99 "OSC_STAT",
100 "CONF_KEY",
101 "TRICKLE",
102 "BREF",
103};
104/*---------------------------------------------------------------------------*/
105static uint8_t
106bcd_to_dec(uint8_t val)
107{
108 return (uint8_t)(((val >> 4) * 10) + (val % 16));
109}
110/*---------------------------------------------------------------------------*/
111static uint8_t
112dec_to_bcd(uint8_t val)
113{
114 return (uint8_t)(((val / 10) << 4) + (val % 10));
115}
116/*---------------------------------------------------------------------------*/
117static uint8_t
118check_leap_year(uint8_t val)
119{
120 return ((val % 4) && (val % 100)) || (val % 400);
121}
122/*---------------------------------------------------------------------------*/
123static int8_t
124ab08_read_reg(uint8_t reg, uint8_t *buf, uint8_t regnum)
125{
127 if(i2c_single_send(AB08XX_ADDR, reg) == I2C_MASTER_ERR_NONE) {
128 if(i2c_burst_receive(AB08XX_ADDR, buf, regnum) == I2C_MASTER_ERR_NONE) {
129 return AB08_SUCCESS;
130 }
131 }
132 return AB08_ERROR;
133}
134/*---------------------------------------------------------------------------*/
135static int8_t
136ab08_write_reg(uint8_t reg, uint8_t *buf, uint8_t regnum)
137{
138 uint8_t i, buff[INT_BUFF_SIZE];
139
140 if(regnum > (INT_BUFF_SIZE - 1)) {
141 return AB08_ERROR;
142 }
143
144 /* FIXME: Replace by single_send/burst_send */
145
146 buff[0] = reg;
147 for(i = 0; i < regnum; i++) {
148 buff[(i + 1)] = buf[i];
149 }
150
152 if(i2c_burst_send(AB08XX_ADDR, buff, (regnum + 1)) == I2C_MASTER_ERR_NONE) {
153 return AB08_SUCCESS;
154 }
155
156 return AB08_ERROR;
157}
158/*---------------------------------------------------------------------------*/
159static void
160write_default_config(void)
161{
162 const ab080x_register_config_t *settings;
163 settings = ab080x_default_setting;
164 uint8_t i, len = (sizeof(ab080x_default_setting) / sizeof(ab080x_register_config_t));
165
166 for(i = 0; i < len; i++) {
167 ab08_write_reg(settings[i].reg, (uint8_t *)&settings[i].val, 1);
168 }
169}
170/*---------------------------------------------------------------------------*/
171static int8_t
172ab08_key_reg(uint8_t unlock)
173{
174 if((unlock != RTCC_CONFKEY_OSCONTROL) && (unlock != RTCC_CONFKEY_SWRESET) &&
175 (unlock != RTCC_CONFKEY_DEFREGS)) {
176 PRINTF("RTC: invalid confkey values\n");
177 return AB08_ERROR;
178 }
179
180 if(ab08_write_reg((CONFIG_MAP_OFFSET + CONF_KEY_ADDR), &unlock, 1)) {
181 PRINTF("RTC: failed to write to confkey register\n");
182 return AB08_ERROR;
183 }
184
185 return AB08_SUCCESS;
186}
187/*---------------------------------------------------------------------------*/
188static int8_t
189ab08_read_status(uint8_t *buf)
190{
191 return ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), buf, 1);
192}
193/*---------------------------------------------------------------------------*/
194static int8_t
195ab08_ctrl1_config(uint8_t cmd)
196{
197 uint8_t ctrl1 = 0;
198
199 if(cmd >= RTCC_CMD_MAX) {
200 return AB08_ERROR;
201 }
202
203 if(ab08_read_reg((CONFIG_MAP_OFFSET + CTRL_1_ADDR), &ctrl1, 1)) {
204 PRINTF("RTC: failed to retrieve CTRL1 register\n");
205 return AB08_ERROR;
206 }
207
208 switch(cmd) {
209 case RTCC_CMD_LOCK:
210 ctrl1 &= ~CTRL1_WRTC;
211 break;
212 case RTCC_CMD_UNLOCK:
213 ctrl1 |= CTRL1_WRTC;
214 break;
215 case RTCC_CMD_ENABLE:
216 ctrl1 &= ~CTRL1_STOP;
217 break;
218 case RTCC_CMD_STOP:
219 ctrl1 |= CTRL1_STOP;
220 break;
221 default:
222 return AB08_ERROR;
223 }
224
225 if(ab08_write_reg((CONFIG_MAP_OFFSET + CTRL_1_ADDR),
226 &ctrl1, 1) == AB08_ERROR) {
227 PRINTF("RTC: failed to write to the CTRL1 register\n");
228 return AB08_ERROR;
229 }
230
231 return AB08_SUCCESS;
232}
233/*---------------------------------------------------------------------------*/
234static int8_t
235ab08_check_td_format(simple_td_map *data, uint8_t alarm_state)
236{
237 /* Using fixed values as these are self-indicative of the variable */
238 if((data->seconds > 59) || (data->minutes > 59) || (data->hours > 23)) {
239 return AB08_ERROR;
240 }
241
242 if((data->months > 12) || (data->weekdays > 7) || (data->day > 31)) {
243 return AB08_ERROR;
244 }
245
246 /* Fixed condition for February (month 2) */
247 if(data->months == 2) {
248 if(check_leap_year(data->years)) {
249 if(data->day > 29) {
250 return AB08_ERROR;
251 }
252 } else {
253 if(data->day > 28) {
254 return AB08_ERROR;
255 }
256 }
257 }
258
259 /* Alarm doesn't care about year */
260 if(!alarm_state) {
261 /* AB08X5 Real-Time Clock Family, page 55 (year up to 2199) */
262 if(data->years > 199) {
263 return AB08_ERROR;
264 }
265 }
266
267 return AB08_SUCCESS;
268}
269/*---------------------------------------------------------------------------*/
270int8_t
271rtcc_set_time_date(simple_td_map *data)
272{
273 uint8_t aux = 0;
274 uint8_t rtc_buffer[RTCC_TD_MAP_SIZE];
275
276 if(ab08_check_td_format(data, 0) == AB08_ERROR) {
277 PRINTF("RTC: Invalid time/date values\n");
278 return AB08_ERROR;
279 }
280
281 if(ab08_read_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
282 &aux, 1) == AB08_ERROR) {
283 PRINTF("RTC: failed to retrieve CONTROL1 register\n");
284 return AB08_ERROR;
285 }
286
287 rtc_buffer[WEEKDAYLS_ADDR] = dec_to_bcd(data->weekdays);
288 rtc_buffer[YEAR_ADDR] = dec_to_bcd(data->years);
289 rtc_buffer[MONTHS_ADDR] = dec_to_bcd(data->months);
290 rtc_buffer[DAY_ADDR] = dec_to_bcd(data->day);
291 rtc_buffer[HOUR_ADDR] = dec_to_bcd(data->hours);
292 rtc_buffer[MIN_ADDR] = dec_to_bcd(data->minutes);
293 rtc_buffer[SEC_ADDR] = dec_to_bcd(data->seconds);
294 rtc_buffer[CENTHS_ADDR] = dec_to_bcd(data->miliseconds);
295
296 /* Check if we are to set the time in 12h/24h format */
297 if(data->mode == RTCC_24H_MODE) {
298 aux &= ~CTRL1_1224;
299 } else {
300 if((data->hours == 0) || (data->hours > 12)) {
301 PRINTF("RTC: Invalid hour configuration (12h mode selected)\n");
302 return AB08_ERROR;
303 }
304 aux |= CTRL1_1224;
305 if(data->mode == RTCC_12H_MODE_PM) {
306 /* Toggle bit for PM */
307 rtc_buffer[HOUR_ADDR] |= RTCC_TOGGLE_PM_BIT;
308 } else {
309 PRINTF("RTC: Invalid time mode selected\n");
310 return AB08_ERROR;
311 }
312 }
313
314 /* Write the 12h/24h config */
315 if(ab08_write_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
316 &aux, 1) == AB08_ERROR) {
317 PRINTF("RTC: failed to write 12h/24h configuration\n");
318 return AB08_ERROR;
319 }
320
321 /* Reading the STATUS register with the CONTROL1.ARST set will clear the
322 * interrupt flags, we write directly to the register without caring its
323 * actual status and let the interrupt handler take care of any pending flag
324 */
325
326 if(ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), &aux, 1) == AB08_ERROR) {
327 PRINTF("RTC: failed to retrieve STATUS register\n");
328 return AB08_ERROR;
329 }
330
331 if(data->century == RTCC_CENTURY_20XX) {
332 aux |= STATUS_CB;
333 } else if(data->century == RTCC_CENTURY_19XX_21XX) {
334 aux |= ~STATUS_CB;
335 } else {
336 PRINTF("RTC: invalid century value\n");
337 return AB08_ERROR;
338 }
339
340 PRINTF("RTC: current STATUS value 0x%02X\n", aux);
341
342 if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), &aux, 1) == AB08_ERROR) {
343 PRINTF("RTC: failed to write century to STATUS register\n");
344 return AB08_ERROR;
345 }
346
347 /* Set the WRTC bit to enable writting to the counters */
348 if(ab08_ctrl1_config(RTCC_CMD_UNLOCK) == AB08_ERROR) {
349 return AB08_ERROR;
350 }
351
352 /* Write the buffers but the mode and century fields (used only for config) */
353 if(ab08_write_reg(CENTHS_ADDR, rtc_buffer,
354 RTCC_TD_MAP_SIZE) == AB08_ERROR) {
355 PRINTF("RTC: failed to write date configuration\n");
356 return AB08_ERROR;
357 }
358
359 /* Lock the RTCC and return */
360 if(ab08_ctrl1_config(RTCC_CMD_LOCK) == AB08_ERROR) {
361 return AB08_ERROR;
362 }
363
364 return AB08_SUCCESS;
365}
366/*---------------------------------------------------------------------------*/
367int8_t
368rtcc_get_time_date(simple_td_map *data)
369{
370 uint8_t rtc_buffer[RTCC_TD_MAP_SIZE];
371
372 if(ab08_read_reg(CENTHS_ADDR, rtc_buffer,
373 RTCC_TD_MAP_SIZE) == AB08_ERROR) {
374 PRINTF("RTC: failed to retrieve date and time values\n");
375 return AB08_ERROR;
376 }
377
378 data->weekdays = bcd_to_dec(rtc_buffer[WEEKDAYLS_ADDR]);
379 data->years = bcd_to_dec(rtc_buffer[YEAR_ADDR]);
380 data->months = bcd_to_dec(rtc_buffer[MONTHS_ADDR]);
381 data->day = bcd_to_dec(rtc_buffer[DAY_ADDR]);
382 data->hours = bcd_to_dec(rtc_buffer[HOUR_ADDR]);
383 data->minutes = bcd_to_dec(rtc_buffer[MIN_ADDR]);
384 data->seconds = bcd_to_dec(rtc_buffer[SEC_ADDR]);
385 data->miliseconds = bcd_to_dec(rtc_buffer[CENTHS_ADDR]);
386
387 return AB08_SUCCESS;
388}
389/*---------------------------------------------------------------------------*/
390int8_t
391rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat,
392 uint8_t trigger)
393{
394 uint8_t aux[4], buf[RTCC_ALARM_MAP_SIZE];
395
396 if((trigger != RTCC_TRIGGER_INT2) && (trigger != RTCC_TRIGGER_INT1) &&
397 (trigger != RTCC_TRIGGER_BOTH)) {
398 PRINTF("RTC: invalid trigger pin\n");
399 return AB08_ERROR;
400 }
401
402 if(state == RTCC_ALARM_OFF) {
403 if(ab08_read_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
404 &aux[0], 1) == AB08_ERROR) {
405 PRINTF("RTC: failed to retrieve INTMASK register\n");
406 return AB08_ERROR;
407 }
408
409 aux[0] &= ~INTMASK_AIE;
410
411 if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
412 &aux[0], 1) == AB08_ERROR) {
413 PRINTF("RTC: failed to clear the alarm config\n");
414 return AB08_ERROR;
415 }
416 return AB08_SUCCESS;
417 }
418
419 if((data == NULL) || (ab08_check_td_format(data, 1) == AB08_ERROR)) {
420 PRINTF("RTC: invalid alarm values\n");
421 return AB08_ERROR;
422 }
423
424 if((state >= RTCC_ALARM_MAX) || (repeat > RTCC_REPEAT_100THS)) {
425 PRINTF("RTC: invalid alarm config type or state\n");
426 return AB08_ERROR;
427 }
428
429 /* Stop the RTCC */
430 ab08_ctrl1_config(RTCC_CMD_STOP);
431
432 buf[WEEKDAYS_ALARM_ADDR] = dec_to_bcd(data->weekdays);
433 buf[MONTHS_ALARM_ADDR] = dec_to_bcd(data->months);
434 buf[DAY_ALARMS_ADDR] = dec_to_bcd(data->day);
435 buf[HOURS_ALARM_ADDR] = dec_to_bcd(data->hours);
436 buf[MINUTES_ALARM_ADDR] = dec_to_bcd(data->minutes);
437 buf[SECONDS_ALARM_ADDR] = dec_to_bcd(data->seconds);
438 buf[HUNDREDTHS_ALARM_ADDR] = dec_to_bcd(data->miliseconds);
439
440 /* Check if the 12h/24h match the current configuration */
441 if(ab08_read_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
442 &aux[0], 1) == AB08_ERROR) {
443 PRINTF("RTC: failed to retrieve CONTROL1 register\n");
444 return AB08_ERROR;
445 }
446
447 if(((aux[0] & CTRL1_1224) && (data->mode == RTCC_24H_MODE)) ||
448 (!(aux[0] & CTRL1_1224) && ((data->mode == RTCC_12H_MODE_AM) ||
449 (data->mode == RTCC_12H_MODE_PM)))) {
450 PRINTF("RTC: 12/24h mode and present date config mismatch\n");
451 return AB08_ERROR;
452 }
453
454 if(data->mode != RTCC_24H_MODE) {
455 if((data->hours == 0) || (data->hours > 12)) {
456 PRINTF("RTC: Invalid hour configuration (12h mode selected)\n");
457 return AB08_ERROR;
458 }
459
460 /* Toggle the PM bit */
461 if(data->mode == RTCC_12H_MODE_PM) {
462 buf[HOURS_ALARM_ADDR] |= RTCC_TOGGLE_PM_BIT;
463 }
464 }
465
466 /* Clear the RPT field */
467 if(ab08_read_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
468 &aux[0], 1) == AB08_ERROR) {
469 PRINTF("RTC: failed to retrieve TIMER CTRL register\n");
470 return AB08_ERROR;
471 }
472
473 aux[0] &= ~COUNTDOWN_TIMER_RPT_SECOND;
474
475 /* AB08XX application manual, table 76 */
476 if(repeat == RTCC_REPEAT_10THS) {
477 buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_10THS_HUNDRETHS;
478 repeat = RTCC_REPEAT_SECOND;
479 } else if(repeat == RTCC_REPEAT_100THS) {
480 buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_100THS_HUNDRETHS;
481 repeat = RTCC_REPEAT_SECOND;
482 }
483
484 if(repeat != RTCC_REPEAT_NONE) {
485 aux[0] |= (repeat << COUNTDOWN_TIMER_RPT_SHIFT);
486 }
487
488 /* We are using as default the level interrupt instead of pulses */
489 /* FIXME: make this selectable */
490 aux[0] |= COUNTDOWN_TIMER_TM;
491 aux[0] &= ~COUNTDOWN_TIMER_TRPT;
492
493 if(ab08_write_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
494 &aux[0], 1) == AB08_ERROR) {
495 PRINTF("RTC: failed to clear the alarm config\n");
496 return AB08_ERROR;
497 }
498
499 if(ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
500 aux, 4) == AB08_ERROR) {
501 PRINTF("RTC: failed to read configuration registers\n");
502 return AB08_ERROR;
503 }
504
505 /* Clear ALM field if any */
506 aux[STATUS_ADDR] &= ~STATUS_ALM;
507
508#if RTCC_CLEAR_INT_MANUALLY
509 aux[CTRL_1_ADDR] &= ~CTRL1_ARST;
510#endif
511
512 /* Clear the AIE alarm bit */
513 aux[INT_MASK_ADDR] &= ~INTMASK_AIE;
514
515 /* Configure Interrupt parameters for Alarm Interrupt Mode in nIRQ
516 * or nAIRQ pins and fixed level until interrupt flag is cleared
517 * RTC_INT1 is connected to the CC2538
518 * RTC_INT2 is connected to the power management PIC in revision B
519 */
520 if (trigger == RTCC_TRIGGER_INT2) {
521 aux[CTRL_2_ADDR] |= CTRL2_OUT2S_NAIRQ_OUTB;
522 /* Only options left enable the INT1 interrupt pin */
523 } else {
524 GPIO_ENABLE_INTERRUPT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
525 ioc_set_over(RTC_INT1_PORT, RTC_INT1_PIN, IOC_OVERRIDE_PUE);
526 NVIC_EnableIRQ(RTC_INT1_VECTOR);
527 }
528
529 if (trigger == RTCC_TRIGGER_INT1) {
530 aux[CTRL_2_ADDR] |= CTRL2_OUT1S_NIRQ_NAIRQ_OUT;
531 } else if (trigger == RTCC_TRIGGER_BOTH) {
532 aux[CTRL_2_ADDR] |= (CTRL2_OUT1S_NIRQ_NAIRQ_OUT + CTRL2_OUT2S_NAIRQ_OUTB);
533 }
534
535 if(repeat != RTCC_REPEAT_NONE) {
536 aux[INT_MASK_ADDR] &= ~INTMASK_IM_LOW;
537 } else {
538 aux[INT_MASK_ADDR] |= INTMASK_IM_LOW;
539 }
540
541 if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), aux, 4) == AB08_ERROR) {
542 PRINTF("RTC: failed to clear alarm config\n");
543 return AB08_ERROR;
544 }
545
546 /* Write to the alarm counters */
547 if(ab08_write_reg((HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET), buf,
548 RTCC_ALARM_MAP_SIZE) == AB08_ERROR) {
549 PRINTF("RTC: failed to set the alarm\n");
550 return AB08_ERROR;
551 }
552
553 /* And finally enable the AIE bit */
554 aux[INT_MASK_ADDR] |= INTMASK_AIE;
555 if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
556 &aux[INT_MASK_ADDR], 1) == AB08_ERROR) {
557 PRINTF("RTC: failed to enable the alarm\n");
558 return AB08_ERROR;
559 }
560
561 /* Enable back the RTCC */
562 ab08_ctrl1_config(RTCC_CMD_ENABLE);
563
564 return AB08_SUCCESS;
565}
566/*---------------------------------------------------------------------------*/
567int8_t
568rtcc_date_increment_seconds(simple_td_map *data, uint16_t seconds)
569{
570 uint16_t aux;
571
572 if(data == NULL) {
573 PRINTF("RTC: invalid argument\n");
574 return AB08_ERROR;
575 }
576
577 if(rtcc_get_time_date(data) == AB08_ERROR) {
578 return AB08_ERROR;
579 }
580
581 /* Nothing to do here but congratulate the user */
582 if(!seconds) {
583 return AB08_SUCCESS;
584 }
585
586 aux = data->seconds + seconds;
587 data->seconds = (uint8_t)(aux % 60);
588
589 /* Add the remainder seconds to the minutes counter */
590 if(aux > 59) {
591 aux /= 60;
592 aux += data->minutes;
593 data->minutes = (uint8_t)(aux % 60);
594 }
595
596 /* Add the remainder minutes to the hours counter */
597 if(aux > 59) {
598 aux /= 60;
599 aux += data->hours;
600 data->hours = (uint8_t)(aux % 24);
601 }
602
603 if(aux > 23) {
604 aux /= 24;
605 aux += data->day;
606
607 if(data->months == 2) {
608 if(check_leap_year(data->years)) {
609 if(aux > 29) {
610 data->day = (uint8_t)(aux % 29);
611 data->months++;
612 }
613 } else if(aux > 28) {
614 data->day = (uint8_t)(aux % 28);
615 data->months++;
616 }
617 } else if((data->months == 4) || (data->months == 6) ||
618 (data->months == 9) || (data->months == 11)) {
619 if(aux > 30) {
620 data->day = (uint8_t)(aux % 30);
621 data->months++;
622 }
623 } else if(aux > 31) {
624 data->day = (uint8_t)(aux % 31);
625 data->months++;
626 }
627 }
628
629 if(data->months > 12) {
630 data->months = data->months % 12;
631 data->years++;
632 }
633 return AB08_SUCCESS;
634}
635/*---------------------------------------------------------------------------*/
636PROCESS(rtcc_int_process, "RTCC interruption process handler");
637/*---------------------------------------------------------------------------*/
638PROCESS_THREAD(rtcc_int_process, ev, data)
639{
640 static uint8_t buf;
643 while(1) {
644 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
645
646 if(ab08_read_status(&buf) == AB08_ERROR) {
647 PRINTF("RTC: failed to retrieve ARST value\n");
648 PROCESS_EXIT();
649 }
650
651 /* We only handle the AIE (alarm interrupt) only */
652 if((buf & STATUS_ALM) && (rtcc_int1_callback != NULL)) {
653#if RTCC_CLEAR_INT_MANUALLY
654 buf &= ~STATUS_ALM;
655 if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
656 &buf, 1) == AB08_ERROR) {
657 PRINTF("RTC: failed to clear the alarm\n");
658 return AB08_ERROR;
659 }
660#endif
661 rtcc_int1_callback(0);
662 }
663 }
664 PROCESS_END();
665}
666/*---------------------------------------------------------------------------*/
667int8_t
668rtcc_print(uint8_t value)
669{
670 uint8_t i, len, reg;
671 char **name;
672 uint8_t rtc_buffer[RTCC_CONFIG_MAP_SIZE];
673
674 if(value >= RTCC_PRINT_MAX) {
675 return AB08_ERROR;
676 }
677
678 switch(value) {
679 case RTCC_PRINT_CONFIG:
680 len = (RTCC_CONFIG_MAP_SIZE - 1);
681 reg = STATUS_ADDR + CONFIG_MAP_OFFSET;
682 name = (char **)ab080x_config_register_name;
683 break;
684 case RTCC_PRINT_ALARM:
685 case RTCC_PRINT_ALARM_DEC:
686 len = RTCC_ALARM_MAP_SIZE;
687 reg = HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET;
688 name = (char **)ab080x_td_register_name;
689 break;
690 case RTCC_PRINT_DATE:
691 case RTCC_PRINT_DATE_DEC:
692 len = RTCC_TD_MAP_SIZE;
693 reg = CENTHS_ADDR;
694 name = (char **)ab080x_td_register_name;
695 break;
696 default:
697 return AB08_ERROR;
698 }
699
700 if(ab08_read_reg(reg, rtc_buffer, len) == AB08_ERROR) {
701 PRINTF("RTC: failed to retrieve values to print\n");
702 return AB08_ERROR;
703 }
704
705 if(value == RTCC_PRINT_ALARM_DEC) {
706 printf("%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
707 bcd_to_dec(rtc_buffer[MONTHS_ALARM_ADDR]),
708 bcd_to_dec(rtc_buffer[DAY_ALARMS_ADDR]),
709 bcd_to_dec(rtc_buffer[WEEKDAYS_ALARM_ADDR]),
710 bcd_to_dec(rtc_buffer[HOURS_ALARM_ADDR]),
711 bcd_to_dec(rtc_buffer[MINUTES_ALARM_ADDR]),
712 bcd_to_dec(rtc_buffer[SECONDS_ALARM_ADDR]),
713 bcd_to_dec(rtc_buffer[HUNDREDTHS_ALARM_ADDR]));
714 return AB08_SUCCESS;
715 }
716
717 if(value == RTCC_PRINT_DATE_DEC) {
718 printf("%02u/%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
719 bcd_to_dec(rtc_buffer[YEAR_ADDR]),
720 bcd_to_dec(rtc_buffer[MONTHS_ADDR]),
721 bcd_to_dec(rtc_buffer[DAY_ADDR]),
722 bcd_to_dec(rtc_buffer[WEEKDAYLS_ADDR]),
723 bcd_to_dec(rtc_buffer[HOUR_ADDR]),
724 bcd_to_dec(rtc_buffer[MIN_ADDR]),
725 bcd_to_dec(rtc_buffer[SEC_ADDR]),
726 bcd_to_dec(rtc_buffer[CENTHS_ADDR]));
727 return AB08_SUCCESS;
728 }
729
730 for(i = 0; i < len; i++) {
731 printf("0x%02X <- %s\n", rtc_buffer[i], name[i]);
732 }
733
734 return AB08_SUCCESS;
735}
736/*---------------------------------------------------------------------------*/
737static void
738rtcc_interrupt_handler(gpio_hal_pin_mask_t pin_mask)
739{
740 process_poll(&rtcc_int_process);
741}
742/*---------------------------------------------------------------------------*/
743int8_t
745{
746 uint8_t aux;
747
748 if(period > RTCC_AUTOCAL_9_MIN) {
749 PRINTF("RTC: invalid autocal value\n");
750 return AB08_ERROR;
751 }
752
753 if(ab08_read_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
754 &aux, 1) == AB08_ERROR) {
755 PRINTF("RTC: failed to read oscillator registers\n");
756 return AB08_ERROR;
757 }
758
759 /* Clear ACAL */
760 aux &= ~OSCONTROL_ACAL_9_MIN;
761
762 /* Unlock the key register */
763 ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
764
765 switch(period) {
766 case RTCC_AUTOCAL_DISABLE:
767 break;
768 case RTCC_AUTOCAL_ONCE:
769 case RTCC_AUTOCAL_17_MIN:
770 aux |= OSCONTROL_ACAL_17_MIN;
771 break;
772 case RTCC_AUTOCAL_9_MIN:
773 aux |= OSCONTROL_ACAL_9_MIN;
774 break;
775 default:
776 return AB08_ERROR;
777 }
778
779 if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
780 &aux, 1) == AB08_ERROR) {
781 PRINTF("RTC: failed to clear the autocalibration\n");
782 return AB08_ERROR;
783 }
784
785 if(period == RTCC_AUTOCAL_ONCE) {
786 clock_delay_usec(10000);
787 ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
788 aux &= ~OSCONTROL_ACAL_9_MIN;
789 if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
790 &aux, 1) == AB08_ERROR) {
791 PRINTF("RTC: failed to clear the autocalibration\n");
792 return AB08_ERROR;
793 }
794 }
795
796 return AB08_SUCCESS;
797}
798/*---------------------------------------------------------------------------*/
799int8_t
800rtcc_set_calibration(uint8_t mode, int32_t adjust)
801{
802 int32_t adjint;
803 uint8_t adjreg[2];
804 uint8_t xtcal;
805
806 if(mode > RTCC_CAL_RC_OSC) {
807 PRINTF("RTC: invalid calibration mode\n");
808 return AB08_ERROR;
809 }
810
811 /* Fixed values dependant on the oscillator source (Application Manual) */
812 if((mode == RTCC_CAL_XT_OSC) && ((adjust <= -610) || (adjust >= 242))) {
813 PRINTF("RTC: invalid adjust value for XT oscillator\n");
814 return AB08_ERROR;
815 }
816
817 if((mode == RTCC_CAL_RC_OSC) && ((adjust <= -65536) || (adjust >= 65520))) {
818 PRINTF("RTC: invalid adjust value for XT oscillator\n");
819 return AB08_ERROR;
820 }
821
822 /* Calibration routine taken from the Application manual */
823 if(adjust < 0) {
824 adjint = ((adjust) * 1000 - 953);
825 } else {
826 adjint = ((adjust) * 1000 + 953);
827 }
828
829 adjint = adjint / 1907;
830
831 if(mode == RTCC_CAL_XT_OSC) {
832 if(adjint > 63) {
833 xtcal = 0;
834 /* CMDX = 1 */
835 adjreg[0] = ((adjint >> 1) & 0x3F) | 0x80;
836 } else if(adjint > -65) {
837 xtcal = 0;
838 adjreg[0] = (adjint & 0x7F);
839 } else if(adjint > -129) {
840 xtcal = 1;
841 adjreg[0] = ((adjint + 64) & 0x7F);
842 } else if(adjint > -193) {
843 xtcal = 2;
844 adjreg[0] = ((adjint + 128) & 0x7F);
845 } else if(adjint > -257) {
846 xtcal = 3;
847 adjreg[0] = ((adjint + 192) & 0x7F);
848 } else {
849 xtcal = 3;
850 adjreg[0] = ((adjint + 192) >> 1) & 0xFF;
851 }
852
853 if(ab08_write_reg((CAL_XT_ADDR + CONFIG_MAP_OFFSET),
854 &adjreg[0], 1) == AB08_ERROR) {
855 PRINTF("RTC: failed to clear the autocalibration\n");
856 return AB08_ERROR;
857 }
858
859 if(ab08_read_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
860 &adjreg[0], 1) == AB08_ERROR) {
861 PRINTF("RTC: failed to read oscillator registers\n");
862 return AB08_ERROR;
863 }
864
865 /* Clear XTCAL and write new value */
866 adjreg[0] &= 0x3F;
867 adjreg[0] |= (xtcal << 6);
868
869 if(ab08_write_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
870 &adjreg[0], 1) == AB08_ERROR) {
871 PRINTF("RTC: failed to clear the autocalibration\n");
872 return AB08_ERROR;
873 }
874 } else if(mode == RTCC_CAL_RC_OSC) {
875 if(adjint > 32767) {
876 adjreg[1] = ((adjint >> 3) & 0xFF);
877 adjreg[0] = ((adjint >> 11) | 0xC0);
878 } else if(adjint > 16383) {
879 adjreg[1] = ((adjint >> 2) & 0xFF);
880 adjreg[0] = ((adjint >> 10) | 0x80);
881 } else if(adjint > 8191) {
882 adjreg[1] = ((adjint >> 1) & 0xFF);
883 adjreg[0] = ((adjint >> 9) | 0x40);
884 } else if(adjint >= 0) {
885 adjreg[1] = ((adjint) & 0xFF);
886 adjreg[0] = (adjint >> 8);
887 } else if(adjint > -8193) {
888 adjreg[1] = ((adjint) & 0xFF);
889 adjreg[0] = (adjint >> 8) & 0x3F;
890 } else if(adjint > -16385) {
891 adjreg[1] = ((adjint >> 1) & 0xFF);
892 adjreg[0] = (adjint >> 9) & 0x7F;
893 } else if(adjint > -32769) {
894 adjreg[1] = ((adjint >> 2) & 0xFF);
895 adjreg[0] = (adjint >> 10) & 0xBF;
896 } else {
897 adjreg[1] = ((adjint >> 3) & 0xFF);
898 adjreg[0] = (adjint >> 11) & 0xFF;
899 }
900
901 if(ab08_write_reg((CAL_RC_HI_ADDR + CONFIG_MAP_OFFSET),
902 adjreg, 2) == AB08_ERROR) {
903 PRINTF("RTC: failed to set the RC calibration\n");
904 return AB08_ERROR;
905 }
906
907 /* This should not happen */
908 } else {
909 return AB08_ERROR;
910 }
911
912 return AB08_SUCCESS;
913}
914/*---------------------------------------------------------------------------*/
915static gpio_hal_event_handler_t rtcc_handler = {
916 .next = NULL,
917 .handler = rtcc_interrupt_handler,
918 .pin_mask = gpio_hal_pin_to_mask(RTC_INT1_PIN) << (RTC_INT1_PORT << 3),
919};
920/*---------------------------------------------------------------------------*/
921int8_t
923{
924 i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
925 I2C_SCL_NORMAL_BUS_SPEED);
926
927#if RTCC_SET_DEFAULT_CONFIG
928 write_default_config();
929#endif
930
931#if RTCC_SET_AUTOCAL
932 rtcc_set_autocalibration(RTCC_AUTOCAL_17_MIN);
933#endif
934
935 /* Initialize interrupts handlers */
936 rtcc_int1_callback = NULL;
937
938 /* Configure the interrupts pins */
939 GPIO_SOFTWARE_CONTROL(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
940 GPIO_SET_INPUT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
941
942 /* Pull-up resistor, detect falling edge */
943 GPIO_DETECT_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
944 GPIO_TRIGGER_SINGLE_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
945 GPIO_DETECT_FALLING(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
946 gpio_hal_register_handler(&rtcc_handler);
947
948 /* Spin process until an interrupt is received */
949 process_start(&rtcc_int_process, NULL);
950
951 return AB08_SUCCESS;
952}
953/*---------------------------------------------------------------------------*/
954/**
955 * @}
956 * @}
957 */
958
Header file with register and macro declarations for the cc2538 GPIO module.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition clock.c:150
#define GPIO_DETECT_FALLING(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on falling edge.
Definition gpio.h:193
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE.
Definition gpio.h:258
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition gpio.h:78
#define GPIO_DETECT_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to detect edge.
Definition gpio.h:154
#define GPIO_TRIGGER_SINGLE_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on single edge (controlled by G...
Definition gpio.h:177
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition gpio.h:201
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
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition i2c.c:49
void i2c_master_enable(void)
Enable master I2C module.
Definition i2c.c:91
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
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition i2c.c:159
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition ioc.c:54
#define IOC_OVERRIDE_PUE
Pull Up Enable.
Definition ioc.h:223
void gpio_hal_register_handler(gpio_hal_event_handler_t *handler)
Register a function to be called whenever a pin triggers an event.
Definition gpio-hal.c:55
uint32_t gpio_hal_pin_mask_t
GPIO pin mask representation.
Definition gpio-hal.h:142
#define gpio_hal_pin_to_mask(pin)
Convert a pin to a pin mask.
Definition gpio-hal.h:255
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition process.h:254
#define PROCESS_EXIT()
Exit the currently running process.
Definition process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:120
#define PROCESS_END()
Define the end of a process.
Definition process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:375
int8_t rtcc_init(void)
Initialize the RTCC, configures the I2C bus, interrupts and registers.
Definition rtcc.c:922
int8_t rtcc_set_calibration(uint8_t mode, int32_t adjust)
Manually calibrate the RTCC.
Definition rtcc.c:800
int8_t rtcc_set_autocalibration(uint8_t period)
Set the autocallibration period.
Definition rtcc.c:744
int8_t rtcc_set_time_date(simple_td_map *data)
Set the time and date.
Definition rtcc.c:271
int8_t rtcc_print(uint8_t value)
Print data from the RTCC module, either from the memory map (values in BCD) or actual readable data (...
Definition rtcc.c:668
int8_t rtcc_date_increment_seconds(simple_td_map *data, uint16_t seconds)
Increments the current date by a number of seconds.
Definition rtcc.c:568
int8_t rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat, uint8_t trigger)
Configure the RTCC to match an alarm counter.
Definition rtcc.c:391
int8_t rtcc_get_time_date(simple_td_map *data)
Get the current time and date.
Definition rtcc.c:368
Header file with declarations for the I2C Control module.
Header file for the LED HAL.
RTCC configuration file.
Header file for the RE-Mote RF antenna switch.
Datatype for GPIO event handlers.
Definition gpio-hal.h:180