From fc6d059d24c0bc28bf2c9238ad247667c9301218 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Mon, 7 Jul 2008 23:38:09 +0000 Subject: [PATCH] Added a clock_seconds() function prototype to core/sys/clock.h, that returns seconds in 32 bit format. On platforms like the MSP430, which has a 16 bit native datatype, this cannot be implemented with an interrupt tick that increments a 32 bit value because access is not atomic. Instead, the MSP430 code increments 16 bit seconds value and converts this into a 32 bit value through an offset calculation. If the new value is smaller than the last check, the offset is incremented by 65536. This change also means that CLOCK_CONF_SECOND must be a power of two because a modulo operation is used inside the periodic tick interrupt handler. --- cpu/msp430/clock.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/cpu/msp430/clock.c b/cpu/msp430/clock.c index 6f1565d13..a8bcee165 100644 --- a/cpu/msp430/clock.c +++ b/cpu/msp430/clock.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * @(#)$Id: clock.c,v 1.13 2008/07/03 23:59:20 adamdunkels Exp $ + * @(#)$Id: clock.c,v 1.14 2008/07/07 23:38:09 adamdunkels Exp $ */ @@ -47,6 +47,8 @@ #define MAX_TICKS (~((clock_time_t)0) / 2) +static volatile unsigned short seconds; + static volatile clock_time_t count = 0; /* last_tar is used for calculating clock_fine, last_ccr might be better? */ static unsigned short last_tar = 0; @@ -58,12 +60,24 @@ interrupt(TIMERA1_VECTOR) timera1 (void) { do { TACCR1 += INTERVAL; ++count; + + /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure + that the modulo operation below becomes a logical and and not + an expensive divide. Algorithm from Wikipedia: + http://en.wikipedia.org/wiki/Power_of_two */ +#if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0 +#error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...). +#error Change CLOCK_CONF_SECOND in contiki-conf.h. +#endif + if(count % CLOCK_CONF_SECOND == 0) { + ++seconds; + } } while((TACCR1 - TAR) > INTERVAL); last_tar = TAR; - if(etimer_pending() - && (etimer_next_expiration_time() - count - 1) > MAX_TICKS) { + if(etimer_pending() && + (etimer_next_expiration_time() - count - 1) > MAX_TICKS) { etimer_request_poll(); LPM4_EXIT; } @@ -170,7 +184,22 @@ clock_set_seconds(unsigned long sec) unsigned long clock_seconds(void) { - return count / CLOCK_SECOND; + static unsigned long offset; + static unsigned long last_time; + unsigned long new_time; + + new_time = seconds + offset; + + /* printf("Seconds %d new_time %lu offset %lu\n", seconds, new_time, offset);*/ + + if(new_time < last_time) { + offset += 0x10000L; + new_time += 0x10000L; + } + + last_time = new_time; + + return new_time; } /*---------------------------------------------------------------------------*/ rtimer_clock_t