Contiki 3.x
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 */
69 void (*rtcc_int1_callback)(uint8_t value);
70 /* -------------------------------------------------------------------------- */
71 static 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 /* -------------------------------------------------------------------------- */
83 static 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 /*---------------------------------------------------------------------------*/
105 static uint8_t
106 bcd_to_dec(uint8_t val)
107 {
108  return (uint8_t)(((val >> 4) * 10) + (val % 16));
109 }
110 /*---------------------------------------------------------------------------*/
111 static uint8_t
112 dec_to_bcd(uint8_t val)
113 {
114  return (uint8_t)(((val / 10) << 4) + (val % 10));
115 }
116 /*---------------------------------------------------------------------------*/
117 static uint8_t
118 check_leap_year(uint8_t val)
119 {
120  return ((val % 4) && (val % 100)) || (val % 400);
121 }
122 /*---------------------------------------------------------------------------*/
123 static uint16_t
124 ab08_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 /*---------------------------------------------------------------------------*/
135 static int8_t
136 ab08_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 /*---------------------------------------------------------------------------*/
159 static void
160 write_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 /*---------------------------------------------------------------------------*/
171 static int8_t
172 ab08_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 /*---------------------------------------------------------------------------*/
188 static int8_t
189 ab08_read_status(uint8_t *buf)
190 {
191  return ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), buf, 1);
192 }
193 /*---------------------------------------------------------------------------*/
194 static int8_t
195 ab08_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 /*---------------------------------------------------------------------------*/
234 static int8_t
235 ab08_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 /*---------------------------------------------------------------------------*/
270 int8_t
271 rtcc_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 /*---------------------------------------------------------------------------*/
367 int8_t
368 rtcc_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 /*---------------------------------------------------------------------------*/
390 int8_t
391 rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat)
392 {
393  uint8_t aux[4], buf[RTCC_ALARM_MAP_SIZE];
394 
395  if(state == RTCC_ALARM_OFF) {
396  if(ab08_read_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
397  &aux[0], 1) == AB08_ERROR) {
398  PRINTF("RTC: failed to retrieve INTMASK register\n");
399  return AB08_ERROR;
400  }
401 
402  aux[0] &= ~INTMASK_AIE;
403 
404  if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
405  &aux[0], 1) == AB08_ERROR) {
406  PRINTF("RTC: failed to clear the alarm config\n");
407  return AB08_ERROR;
408  }
409  return AB08_SUCCESS;
410  }
411 
412  if((data == NULL) || (ab08_check_td_format(data, 1) == AB08_ERROR)) {
413  PRINTF("RTC: invalid alarm values\n");
414  return AB08_ERROR;
415  }
416 
417  if((state >= RTCC_ALARM_MAX) || (repeat >= RTCC_REPEAT_100THS)) {
418  PRINTF("RTC: invalid alarm config type or state\n");
419  return AB08_ERROR;
420  }
421 
422  /* Stop the RTCC */
423  ab08_ctrl1_config(RTCC_CMD_STOP);
424 
425  buf[WEEKDAYS_ALARM_ADDR] = dec_to_bcd(data->weekdays);
426  buf[MONTHS_ALARM_ADDR] = dec_to_bcd(data->months);
427  buf[DAY_ALARMS_ADDR] = dec_to_bcd(data->day);
428  buf[HOURS_ALARM_ADDR] = dec_to_bcd(data->hours);
429  buf[MINUTES_ALARM_ADDR] = dec_to_bcd(data->minutes);
430  buf[SECONDS_ALARM_ADDR] = dec_to_bcd(data->seconds);
431  buf[HUNDREDTHS_ALARM_ADDR] = dec_to_bcd(data->miliseconds);
432 
433  /* Check if the 12h/24h match the current configuration */
434  if(ab08_read_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
435  &aux[0], 1) == AB08_ERROR) {
436  PRINTF("RTC: failed to retrieve CONTROL1 register\n");
437  return AB08_ERROR;
438  }
439 
440  if(((aux[0] & CTRL1_1224) && (data->mode == RTCC_24H_MODE)) ||
441  (!(aux[0] & CTRL1_1224) && ((data->mode == RTCC_12H_MODE_AM) ||
442  (data->mode == RTCC_12H_MODE_PM)))) {
443  PRINTF("RTC: 12/24h mode and present date config mismatch\n");
444  return AB08_ERROR;
445  }
446 
447  if(data->mode != RTCC_24H_MODE) {
448  if((data->hours == 0) || (data->hours > 12)) {
449  PRINTF("RTC: Invalid hour configuration (12h mode selected)\n");
450  return AB08_ERROR;
451  }
452 
453  /* Toggle the PM bit */
454  if(data->mode == RTCC_12H_MODE_PM) {
455  buf[HOURS_ALARM_ADDR] |= RTCC_TOGGLE_PM_BIT;
456  }
457  }
458 
459  /* Clear the RPT field */
460  if(ab08_read_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
461  &aux[0], 1) == AB08_ERROR) {
462  PRINTF("RTC: failed to retrieve TIMER CTRL register\n");
463  return AB08_ERROR;
464  }
465 
466  aux[0] &= ~COUNTDOWN_TIMER_RPT_SECOND;
467 
468  /* AB08XX application manual, table 76 */
469  if(repeat == RTCC_REPEAT_10THS) {
470  buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_10THS_HUNDRETHS;
471  repeat = RTCC_REPEAT_SECOND;
472  } else if(repeat == RTCC_REPEAT_100THS) {
473  buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_100THS_HUNDRETHS;
474  repeat = RTCC_REPEAT_SECOND;
475  }
476 
477  if(repeat != RTCC_REPEAT_NONE) {
478  aux[0] |= (repeat << COUNTDOWN_TIMER_RPT_SHIFT);
479  }
480 
481  /* We are using as default the level interrupt instead of pulses */
482  /* FIXME: make this selectable */
483  aux[0] |= COUNTDOWN_TIMER_TM;
484  aux[0] &= ~COUNTDOWN_TIMER_TRPT;
485 
486  if(ab08_write_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
487  &aux[0], 1) == AB08_ERROR) {
488  PRINTF("RTC: failed to clear the alarm config\n");
489  return AB08_ERROR;
490  }
491 
492  if(ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
493  aux, 4) == AB08_ERROR) {
494  PRINTF("RTC: failed to read configuration registers\n");
495  return AB08_ERROR;
496  }
497 
498  /* Clear ALM field if any */
499  aux[STATUS_ADDR] &= ~STATUS_ALM;
500 
501 #if RTCC_CLEAR_INT_MANUALLY
502  aux[CTRL_1_ADDR] &= ~CTRL1_ARST;
503 #endif
504 
505  /* Clear the AIE alarm bit */
506  aux[INT_MASK_ADDR] &= ~INTMASK_AIE;
507 
508  /* Configure Interrupt parameters for Alarm Interrupt Mode in nIRQ pin,
509  * and fixed level until interrupt flag is cleared
510  */
511 
512  /* Enable nIRQ if at least one interrupt is enabled */
513  aux[CTRL_2_ADDR] |= CTRL2_OUT1S_NIRQ_NAIRQ_OUT;
514 
515  if(repeat != RTCC_REPEAT_NONE) {
516  aux[INT_MASK_ADDR] &= ~INTMASK_IM_LOW;
517  } else {
518  aux[INT_MASK_ADDR] |= INTMASK_IM_LOW;
519  }
520 
521  if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), aux, 4) == AB08_ERROR) {
522  PRINTF("RTC: failed to clear alarm config\n");
523  return AB08_ERROR;
524  }
525 
526  /* Enable interrupts */
527  GPIO_ENABLE_INTERRUPT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
528  ioc_set_over(RTC_INT1_PORT, RTC_INT1_PIN, IOC_OVERRIDE_PUE);
529  nvic_interrupt_enable(RTC_INT1_VECTOR);
530 
531  /* Write to the alarm counters */
532  if(ab08_write_reg((HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET), buf,
533  RTCC_ALARM_MAP_SIZE) == AB08_ERROR) {
534  PRINTF("RTC: failed to set the alarm\n");
535  return AB08_ERROR;
536  }
537 
538  /* And finally enable the AIE bit */
539  aux[INT_MASK_ADDR] |= INTMASK_AIE;
540  if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
541  &aux[INT_MASK_ADDR], 1) == AB08_ERROR) {
542  PRINTF("RTC: failed to enable the alarm\n");
543  return AB08_ERROR;
544  }
545 
546  /* Enable back the RTCC */
547  ab08_ctrl1_config(RTCC_CMD_ENABLE);
548 
549  return AB08_SUCCESS;
550 }
551 /*---------------------------------------------------------------------------*/
552 PROCESS(rtcc_int_process, "RTCC interruption process handler");
553 /*---------------------------------------------------------------------------*/
554 PROCESS_THREAD(rtcc_int_process, ev, data)
555 {
556  static uint8_t buf;
558  PROCESS_BEGIN();
559  while(1) {
560  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
561 
562  if(ab08_read_status(&buf) == AB08_ERROR) {
563  PRINTF("RTC: failed to retrieve ARST value\n");
564  PROCESS_EXIT();
565  }
566 
567  /* We only handle the AIE (alarm interrupt) only */
568  if((buf & STATUS_ALM) && (rtcc_int1_callback != NULL)) {
569 #if RTCC_CLEAR_INT_MANUALLY
570  buf &= ~STATUS_ALM;
571  if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
572  &buf, 1) == AB08_ERROR) {
573  PRINTF("RTC: failed to clear the alarm\n");
574  return AB08_ERROR;
575  }
576 #endif
577  rtcc_int1_callback(0);
578  }
579  }
580  PROCESS_END();
581 }
582 /*---------------------------------------------------------------------------*/
583 int8_t
584 rtcc_print(uint8_t value)
585 {
586  uint8_t i, len, reg;
587  char **name;
588  uint8_t rtc_buffer[RTCC_CONFIG_MAP_SIZE];
589 
590  if(value >= RTCC_PRINT_MAX) {
591  return AB08_ERROR;
592  }
593 
594  switch(value) {
595  case RTCC_PRINT_CONFIG:
596  len = (RTCC_CONFIG_MAP_SIZE - 1);
597  reg = STATUS_ADDR + CONFIG_MAP_OFFSET;
598  name = (char **)ab080x_config_register_name;
599  break;
600  case RTCC_PRINT_ALARM:
601  case RTCC_PRINT_ALARM_DEC:
602  len = RTCC_ALARM_MAP_SIZE;
603  reg = HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET;
604  name = (char **)ab080x_td_register_name;
605  break;
606  case RTCC_PRINT_DATE:
607  case RTCC_PRINT_DATE_DEC:
608  len = RTCC_TD_MAP_SIZE;
609  reg = CENTHS_ADDR;
610  name = (char **)ab080x_td_register_name;
611  break;
612  default:
613  return AB08_ERROR;
614  }
615 
616  if(ab08_read_reg(reg, rtc_buffer, len) == AB08_ERROR) {
617  PRINTF("RTC: failed to retrieve values to print\n");
618  return AB08_ERROR;
619  }
620 
621  if(value == RTCC_PRINT_ALARM_DEC) {
622  printf("%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
623  bcd_to_dec(rtc_buffer[MONTHS_ALARM_ADDR]),
624  bcd_to_dec(rtc_buffer[DAY_ALARMS_ADDR]),
625  bcd_to_dec(rtc_buffer[WEEKDAYS_ALARM_ADDR]),
626  bcd_to_dec(rtc_buffer[HOURS_ALARM_ADDR]),
627  bcd_to_dec(rtc_buffer[MINUTES_ALARM_ADDR]),
628  bcd_to_dec(rtc_buffer[SECONDS_ALARM_ADDR]),
629  bcd_to_dec(rtc_buffer[HUNDREDTHS_ALARM_ADDR]));
630  return AB08_SUCCESS;
631  }
632 
633  if(value == RTCC_PRINT_DATE_DEC) {
634  printf("%02u/%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
635  bcd_to_dec(rtc_buffer[YEAR_ADDR]),
636  bcd_to_dec(rtc_buffer[MONTHS_ADDR]),
637  bcd_to_dec(rtc_buffer[DAY_ADDR]),
638  bcd_to_dec(rtc_buffer[WEEKDAYLS_ADDR]),
639  bcd_to_dec(rtc_buffer[HOUR_ADDR]),
640  bcd_to_dec(rtc_buffer[MIN_ADDR]),
641  bcd_to_dec(rtc_buffer[SEC_ADDR]),
642  bcd_to_dec(rtc_buffer[CENTHS_ADDR]));
643  return AB08_SUCCESS;
644  }
645 
646  for(i = 0; i < len; i++) {
647  printf("0x%02X <- %s\n", rtc_buffer[i], name[i]);
648  }
649 
650  return AB08_SUCCESS;
651 }
652 /*---------------------------------------------------------------------------*/
653 static void
654 rtcc_interrupt_handler(uint8_t port, uint8_t pin)
655 {
656  process_poll(&rtcc_int_process);
657 }
658 /*---------------------------------------------------------------------------*/
659 int8_t
661 {
662  uint8_t aux;
663 
664  if(period > RTCC_AUTOCAL_9_MIN) {
665  PRINTF("RTC: invalid autocal value\n");
666  return AB08_ERROR;
667  }
668 
669  if(ab08_read_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
670  &aux, 1) == AB08_ERROR) {
671  PRINTF("RTC: failed to read oscillator registers\n");
672  return AB08_ERROR;
673  }
674 
675  /* Clear ACAL */
676  aux &= ~OSCONTROL_ACAL_9_MIN;
677 
678  /* Unlock the key register */
679  ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
680 
681  switch(period) {
682  case RTCC_AUTOCAL_DISABLE:
683  break;
684  case RTCC_AUTOCAL_ONCE:
685  case RTCC_AUTOCAL_17_MIN:
686  aux |= OSCONTROL_ACAL_17_MIN;
687  break;
688  case RTCC_AUTOCAL_9_MIN:
689  aux |= OSCONTROL_ACAL_9_MIN;
690  break;
691  default:
692  return AB08_ERROR;
693  }
694 
695  if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
696  &aux, 1) == AB08_ERROR) {
697  PRINTF("RTC: failed to clear the autocalibration\n");
698  return AB08_ERROR;
699  }
700 
701  if(period == RTCC_AUTOCAL_ONCE) {
702  clock_delay_usec(10000);
703  ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
704  aux &= ~OSCONTROL_ACAL_9_MIN;
705  if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
706  &aux, 1) == AB08_ERROR) {
707  PRINTF("RTC: failed to clear the autocalibration\n");
708  return AB08_ERROR;
709  }
710  }
711 
712  return AB08_SUCCESS;
713 }
714 /*---------------------------------------------------------------------------*/
715 int8_t
716 rtcc_set_calibration(uint8_t mode, int32_t adjust)
717 {
718  int32_t adjint;
719  uint8_t adjreg[2];
720  uint8_t xtcal;
721 
722  if(mode > RTCC_CAL_RC_OSC) {
723  PRINTF("RTC: invalid calibration mode\n");
724  return AB08_ERROR;
725  }
726 
727  /* Fixed values dependant on the oscillator source (Application Manual) */
728  if((mode == RTCC_CAL_XT_OSC) && ((adjust <= -610) || (adjust >= 242))) {
729  PRINTF("RTC: invalid adjust value for XT oscillator\n");
730  return AB08_ERROR;
731  }
732 
733  if((mode == RTCC_CAL_RC_OSC) && ((adjust <= -65536) || (adjust >= 65520))) {
734  PRINTF("RTC: invalid adjust value for XT oscillator\n");
735  return AB08_ERROR;
736  }
737 
738  /* Calibration routine taken from the Application manual */
739  if(adjust < 0) {
740  adjint = ((adjust) * 1000 - 953);
741  } else {
742  adjint = ((adjust) * 1000 + 953);
743  }
744 
745  adjint = adjint / 1907;
746 
747  if(mode == RTCC_CAL_XT_OSC) {
748  if(adjint > 63) {
749  xtcal = 0;
750  /* CMDX = 1 */
751  adjreg[0] = ((adjint >> 1) & 0x3F) | 0x80;
752  } else if(adjint > -65) {
753  xtcal = 0;
754  adjreg[0] = (adjint & 0x7F);
755  } else if(adjint > -129) {
756  xtcal = 1;
757  adjreg[0] = ((adjint + 64) & 0x7F);
758  } else if(adjint > -193) {
759  xtcal = 2;
760  adjreg[0] = ((adjint + 128) & 0x7F);
761  } else if(adjint > -257) {
762  xtcal = 3;
763  adjreg[0] = ((adjint + 192) & 0x7F);
764  } else {
765  xtcal = 3;
766  adjreg[0] = ((adjint + 192) >> 1) & 0xFF;
767  }
768 
769  if(ab08_write_reg((CAL_XT_ADDR + CONFIG_MAP_OFFSET),
770  &adjreg[0], 1) == AB08_ERROR) {
771  PRINTF("RTC: failed to clear the autocalibration\n");
772  return AB08_ERROR;
773  }
774 
775  if(ab08_read_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
776  &adjreg[0], 1) == AB08_ERROR) {
777  PRINTF("RTC: failed to read oscillator registers\n");
778  return AB08_ERROR;
779  }
780 
781  /* Clear XTCAL and write new value */
782  adjreg[0] &= 0x3F;
783  adjreg[0] |= (xtcal << 6);
784 
785  if(ab08_write_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
786  &adjreg[0], 1) == AB08_ERROR) {
787  PRINTF("RTC: failed to clear the autocalibration\n");
788  return AB08_ERROR;
789  }
790  } else if(mode == RTCC_CAL_RC_OSC) {
791  if(adjint > 32767) {
792  adjreg[1] = ((adjint >> 3) & 0xFF);
793  adjreg[0] = ((adjint >> 11) | 0xC0);
794  } else if(adjint > 16383) {
795  adjreg[1] = ((adjint >> 2) & 0xFF);
796  adjreg[0] = ((adjint >> 10) | 0x80);
797  } else if(adjint > 8191) {
798  adjreg[1] = ((adjint >> 1) & 0xFF);
799  adjreg[0] = ((adjint >> 9) | 0x40);
800  } else if(adjint >= 0) {
801  adjreg[1] = ((adjint) & 0xFF);
802  adjreg[0] = (adjint >> 8);
803  } else if(adjint > -8193) {
804  adjreg[1] = ((adjint) & 0xFF);
805  adjreg[0] = (adjint >> 8) & 0x3F;
806  } else if(adjint > -16385) {
807  adjreg[1] = ((adjint >> 1) & 0xFF);
808  adjreg[0] = (adjint >> 9) & 0x7F;
809  } else if(adjint > -32769) {
810  adjreg[1] = ((adjint >> 2) & 0xFF);
811  adjreg[0] = (adjint >> 10) & 0xBF;
812  } else {
813  adjreg[1] = ((adjint >> 3) & 0xFF);
814  adjreg[0] = (adjint >> 11) & 0xFF;
815  }
816 
817  if(ab08_write_reg((CAL_RC_HI_ADDR + CONFIG_MAP_OFFSET),
818  adjreg, 2) == AB08_ERROR) {
819  PRINTF("RTC: failed to set the RC calibration\n");
820  return AB08_ERROR;
821  }
822 
823  /* This should not happen */
824  } else {
825  return AB08_ERROR;
826  }
827 
828  return AB08_SUCCESS;
829 }
830 /*---------------------------------------------------------------------------*/
831 int8_t
833 {
834  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
835  I2C_SCL_NORMAL_BUS_SPEED);
836 
837 #if RTCC_SET_DEFAULT_CONFIG
838  write_default_config();
839 #endif
840 
841 #if RTCC_SET_AUTOCAL
842  rtcc_set_autocalibration(RTCC_AUTOCAL_17_MIN);
843 #endif
844 
845  /* Initialize interrupts handlers */
846  rtcc_int1_callback = NULL;
847 
848  /* Configure the interrupts pins */
849  GPIO_SOFTWARE_CONTROL(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
850  GPIO_SET_INPUT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
851 
852  /* Pull-up resistor, detect falling edge */
853  GPIO_DETECT_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
854  GPIO_TRIGGER_SINGLE_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
855  GPIO_DETECT_FALLING(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
856  gpio_register_callback(rtcc_interrupt_handler, RTC_INT1_PORT, RTC_INT1_PIN);
857 
858  /* Spin process until an interrupt is received */
859  process_start(&rtcc_int_process, NULL);
860 
861  return AB08_SUCCESS;
862 }
863 /*---------------------------------------------------------------------------*/
864 /**
865  * @}
866  * @}
867  */
868 
#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:178
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:202
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:93
#define IOC_OVERRIDE_PUE
Pull Up Enable.
Definition: ioc.h:223
#define GPIO_DETECT_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to detect edge.
Definition: gpio.h:155
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int8_t rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat)
Configure the RTCC to match an alarm counter.
Definition: rtcc.c:391
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#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:194
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:584
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
int8_t rtcc_set_calibration(uint8_t mode, int32_t adjust)
Manually calibrate the RTCC.
Definition: rtcc.c:716
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
RTCC configuration file.
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
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
#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:259
int8_t rtcc_set_autocalibration(uint8_t period)
Set the autocallibration period.
Definition: rtcc.c:660
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void nvic_interrupt_enable(uint32_t intr)
Enables interrupt intr.
Definition: nvic.c:64
int8_t rtcc_get_time_date(simple_td_map *data)
Get the current time and date.
Definition: rtcc.c:368
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
void gpio_register_callback(gpio_callback_t f, uint8_t port, uint8_t pin)
Register GPIO callback.
Definition: gpio.c:56
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:94
int8_t rtcc_init(void)
Initialize the RTCC, configures the I2C bus, interrupts and registers.
Definition: rtcc.c:832
Header file for the RE-Mote RF antenna switch.
int8_t rtcc_set_time_date(simple_td_map *data)
Set the time and date.
Definition: rtcc.c:271
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120