2006-06-18 00:41:10 +02:00
|
|
|
|
|
|
|
#include "sys/clock.h"
|
2008-10-14 21:06:51 +02:00
|
|
|
#include "dev/clock-avr.h"
|
2006-06-18 00:41:10 +02:00
|
|
|
#include "sys/etimer.h"
|
|
|
|
|
|
|
|
#include <avr/io.h>
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
|
2011-09-10 18:44:49 +02:00
|
|
|
/*
|
|
|
|
CLOCK_SECOND is the number of ticks per second.
|
|
|
|
It is defined through CONF_CLOCK_SECOND in the contiki-conf.h for each platform.
|
|
|
|
The usual AVR defaults are 128 or 125 ticks per second, counting a prescaled CPU clock
|
|
|
|
using the 8 bit timer0.
|
|
|
|
|
|
|
|
As clock_time_t is an unsigned 16 bit data type, intervals up to 512 or 524 seconds
|
|
|
|
can be measured with ~8 millisecond precision.
|
|
|
|
For longer intervals a 32 bit global is incremented every second.
|
|
|
|
|
|
|
|
clock-avr.h contains the specific setup code for each mcu.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* count is a 16 bit tick counter that wraps every ~10 minutes, returned by clock_time() */
|
2010-06-18 19:30:30 +02:00
|
|
|
static volatile clock_time_t count;
|
2011-09-10 18:44:49 +02:00
|
|
|
/* scount is the 8 bit counter that counts ticks modulo CLOCK_SECONDS */
|
2010-06-18 19:30:30 +02:00
|
|
|
static volatile uint8_t scount;
|
2011-09-10 18:44:49 +02:00
|
|
|
/* seconds is the number of seconds since startup, returned by clock_seconds() */
|
2010-06-18 19:30:30 +02:00
|
|
|
volatile unsigned long seconds;
|
2011-09-10 18:44:49 +02:00
|
|
|
/* sleepseconds is the number of seconds sleeping since startup, available globally */
|
2010-12-23 20:41:07 +01:00
|
|
|
long sleepseconds;
|
2010-06-18 19:30:30 +02:00
|
|
|
|
|
|
|
/* Set RADIOSTATS to monitor radio on time (must also be set in the radio driver) */
|
2011-07-24 17:43:17 +02:00
|
|
|
#if RF230BB && AVR_WEBSERVER
|
2010-02-26 22:38:57 +01:00
|
|
|
#define RADIOSTATS 1
|
|
|
|
#endif
|
2011-03-13 18:07:32 +01:00
|
|
|
|
2010-02-12 15:37:50 +01:00
|
|
|
#if RADIOSTATS
|
2010-06-18 19:30:30 +02:00
|
|
|
static volatile uint8_t rcount;
|
|
|
|
volatile unsigned long radioontime;
|
2010-02-26 22:38:57 +01:00
|
|
|
extern uint8_t RF230_receive_on;
|
2010-02-12 15:37:50 +01:00
|
|
|
#endif
|
2006-06-18 00:41:10 +02:00
|
|
|
|
2011-08-13 17:38:38 +02:00
|
|
|
/* Set RADIO_CONF_CALIBRATE_INTERVAL for periodic calibration of the PLL during extended radio on time.
|
|
|
|
* The RF230 data sheet suggests every 5 minutes if the temperature is fluctuating.
|
|
|
|
* At present the specified interval is ignored, and an 8 bit counter gives 256 second intervals.
|
2011-03-13 18:07:32 +01:00
|
|
|
* Actual calibration is done by the driver on the next transmit request.
|
|
|
|
*/
|
2011-08-13 17:38:38 +02:00
|
|
|
#if RADIO_CONF_CALIBRATE_INTERVAL
|
2011-03-13 18:07:32 +01:00
|
|
|
extern volatile uint8_t rf230_calibrate;
|
|
|
|
static uint8_t calibrate_interval;
|
|
|
|
#endif
|
|
|
|
|
2011-09-10 18:44:49 +02:00
|
|
|
#if 0
|
2010-12-22 18:09:03 +01:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* This routine can be called to add seconds to the clock after a sleep
|
|
|
|
* of an integral number of seconds.
|
|
|
|
*/
|
2010-12-22 17:50:30 +01:00
|
|
|
void clock_adjust_seconds(uint8_t howmany) {
|
|
|
|
seconds += howmany;
|
2010-12-23 20:41:07 +01:00
|
|
|
sleepseconds +=howmany;
|
2011-09-10 18:44:49 +02:00
|
|
|
count += howmany * CLOCK_SECOND;
|
2010-12-22 17:50:30 +01:00
|
|
|
#if RADIOSTATS
|
|
|
|
if (RF230_receive_on) radioontime += howmany;
|
|
|
|
#endif
|
|
|
|
}
|
2011-09-10 18:44:49 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* This routine can be called to add ticks to the clock after a sleep.
|
2011-12-01 15:58:55 +01:00
|
|
|
* Leap ticks or seconds can (rarely) be introduced if the ISR is not blocked.
|
2011-09-10 18:44:49 +02:00
|
|
|
*/
|
|
|
|
void clock_adjust_ticks(uint16_t howmany) {
|
2011-12-01 15:58:55 +01:00
|
|
|
// uint8_t sreg = SREG;cli();
|
2011-09-10 18:44:49 +02:00
|
|
|
count += howmany;
|
2011-12-01 15:58:55 +01:00
|
|
|
howmany+= scount;
|
|
|
|
while(howmany >= CLOCK_SECOND) {
|
|
|
|
howmany -= CLOCK_SECOND;
|
2011-09-10 18:44:49 +02:00
|
|
|
seconds++;
|
|
|
|
sleepseconds++;
|
|
|
|
#if RADIOSTATS
|
|
|
|
if (RF230_receive_on) radioontime += 1;
|
|
|
|
#endif
|
|
|
|
}
|
2011-12-01 15:58:55 +01:00
|
|
|
scount = howmany;
|
|
|
|
// SREG=sreg;
|
2011-09-10 18:44:49 +02:00
|
|
|
}
|
2006-06-18 00:41:10 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2008-10-14 21:06:51 +02:00
|
|
|
//SIGNAL(SIG_OUTPUT_COMPARE0)
|
|
|
|
ISR(AVR_OUTPUT_COMPARE_INT)
|
2006-06-18 00:41:10 +02:00
|
|
|
{
|
2009-04-06 15:08:42 +02:00
|
|
|
count++;
|
2011-12-01 15:58:55 +01:00
|
|
|
if(++scount >= CLOCK_SECOND) {
|
2009-04-06 15:08:42 +02:00
|
|
|
scount = 0;
|
2011-03-13 18:07:32 +01:00
|
|
|
seconds++;
|
|
|
|
}
|
2012-01-10 18:42:27 +01:00
|
|
|
|
|
|
|
#if F_CPU == 0x800000 && USE_32K_CRYSTAL
|
|
|
|
/* Special routine to phase lock CPU to 32768 watch crystal.
|
|
|
|
We are interrupting 128 times per second.
|
|
|
|
If RTIMER_ARCH_SECOND is a multiple of 128 we can use the residual modulo
|
|
|
|
128 to determine whether the clock is too fast or too slow.
|
|
|
|
E.g. for 8192 the phase should be constant modulo 0x40
|
|
|
|
OSCCAL is started in the lower range at 90, allowed to stabilize, then
|
|
|
|
rapidly raised or lowered based on the phase comparison.
|
|
|
|
It gives less phase noise to do this every tick and doesn't seem to hurt anything.
|
|
|
|
*/
|
|
|
|
#include "rtimer-arch.h"
|
|
|
|
{
|
|
|
|
volatile static uint8_t lockcount;
|
|
|
|
volatile static int16_t last_phase;
|
|
|
|
volatile static uint8_t osccalhigh,osccallow;
|
|
|
|
if (seconds < 60) { //give a minute to stabilize
|
|
|
|
if(++lockcount >= 8192UL*128/RTIMER_ARCH_SECOND) {
|
|
|
|
lockcount=0;
|
|
|
|
rtimer_phase = TCNT3 & 0x0fff;
|
|
|
|
if (seconds < 2) OSCCAL=100;
|
|
|
|
if (last_phase > rtimer_phase) osccalhigh=++OSCCAL; else osccallow=--OSCCAL;
|
|
|
|
last_phase = rtimer_phase;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#if TICK_MODULO
|
|
|
|
static uint8_t lock_clock;
|
|
|
|
if (++lock_clock>=TICK_MODULO) {
|
|
|
|
lock_clock=0;
|
|
|
|
#endif
|
|
|
|
uint8_t error = (TCNT3 - last_phase) & 0x3f;
|
|
|
|
if (error == 0) {
|
|
|
|
} else if (error<32) {
|
|
|
|
OSCCAL=osccallow-1;
|
|
|
|
} else {
|
|
|
|
OSCCAL=osccalhigh+1;
|
|
|
|
}
|
|
|
|
#if TICK_MODULO
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-08-13 17:38:38 +02:00
|
|
|
#if RADIO_CONF_CALIBRATE_INTERVAL
|
2011-03-13 18:07:32 +01:00
|
|
|
if (++calibrate_interval==0) {
|
|
|
|
rf230_calibrate=1;
|
2009-04-06 15:08:42 +02:00
|
|
|
}
|
2011-03-13 18:07:32 +01:00
|
|
|
#endif
|
2010-02-12 15:37:50 +01:00
|
|
|
#if RADIOSTATS
|
2010-02-26 22:38:57 +01:00
|
|
|
if (RF230_receive_on) {
|
2011-12-01 15:58:55 +01:00
|
|
|
if (++rcount >= CLOCK_SECOND) {
|
2010-02-12 15:37:50 +01:00
|
|
|
rcount=0;
|
2011-03-13 18:07:32 +01:00
|
|
|
radioontime++;
|
2010-02-12 15:37:50 +01:00
|
|
|
}
|
2011-03-13 19:08:02 +01:00
|
|
|
}
|
2010-02-12 15:37:50 +01:00
|
|
|
#endif
|
2011-03-13 18:07:32 +01:00
|
|
|
|
|
|
|
#if 1
|
|
|
|
/* gcc will save all registers on the stack if an external routine is called */
|
2006-06-18 00:41:10 +02:00
|
|
|
if(etimer_pending()) {
|
|
|
|
etimer_request_poll();
|
|
|
|
}
|
2011-03-13 18:07:32 +01:00
|
|
|
#else
|
|
|
|
/* doing this locally saves 9 pushes and 9 pops, but these etimer.c and process.c variables have to lose the static qualifier */
|
|
|
|
extern struct etimer *timerlist;
|
|
|
|
extern volatile unsigned char poll_requested;
|
|
|
|
|
|
|
|
#define PROCESS_STATE_NONE 0
|
|
|
|
#define PROCESS_STATE_RUNNING 1
|
|
|
|
#define PROCESS_STATE_CALLED 2
|
|
|
|
|
|
|
|
if (timerlist) {
|
|
|
|
if(etimer_process.state == PROCESS_STATE_RUNNING ||
|
|
|
|
etimer_process.state == PROCESS_STATE_CALLED) {
|
|
|
|
etimer_process.needspoll = 1;
|
|
|
|
poll_requested = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-06-18 00:41:10 +02:00
|
|
|
}
|
2006-12-22 18:04:38 +01:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void
|
|
|
|
clock_init(void)
|
|
|
|
{
|
|
|
|
cli ();
|
2008-10-14 21:06:51 +02:00
|
|
|
OCRSetup();
|
2010-06-18 19:30:30 +02:00
|
|
|
//scount = count = 0;
|
2006-12-22 18:04:38 +01:00
|
|
|
sei ();
|
2006-06-18 00:41:10 +02:00
|
|
|
}
|
2006-12-22 18:04:38 +01:00
|
|
|
|
2006-06-18 00:41:10 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
clock_time_t
|
|
|
|
clock_time(void)
|
|
|
|
{
|
2009-04-06 15:08:42 +02:00
|
|
|
clock_time_t tmp;
|
|
|
|
do {
|
|
|
|
tmp = count;
|
|
|
|
} while(tmp != count);
|
|
|
|
return tmp;
|
2006-06-18 00:41:10 +02:00
|
|
|
}
|
2011-09-10 18:44:49 +02:00
|
|
|
#if 0
|
2006-06-18 00:41:10 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2006-12-22 18:04:38 +01:00
|
|
|
/**
|
|
|
|
* Delay the CPU for a multiple of TODO
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
clock_delay(unsigned int i)
|
|
|
|
{
|
2007-01-24 17:28:51 +01:00
|
|
|
for (; i > 0; i--) { /* Needs fixing XXX */
|
|
|
|
unsigned j;
|
|
|
|
for (j = 50; j > 0; j--)
|
|
|
|
asm volatile("nop");
|
|
|
|
}
|
2006-12-22 18:04:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2011-09-10 18:44:49 +02:00
|
|
|
* Wait for a number of clock ticks.
|
2006-12-22 18:04:38 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
clock_wait(int i)
|
|
|
|
{
|
|
|
|
clock_time_t start;
|
|
|
|
|
|
|
|
start = clock_time();
|
|
|
|
while(clock_time() - start < (clock_time_t)i);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void
|
|
|
|
clock_set_seconds(unsigned long sec)
|
|
|
|
{
|
2011-09-10 18:44:49 +02:00
|
|
|
seconds = sec;
|
2006-12-22 18:04:38 +01:00
|
|
|
}
|
2011-09-10 18:44:49 +02:00
|
|
|
#endif
|
2006-12-22 18:04:38 +01:00
|
|
|
|
|
|
|
unsigned long
|
|
|
|
clock_seconds(void)
|
|
|
|
{
|
2009-04-06 15:08:42 +02:00
|
|
|
unsigned long tmp;
|
|
|
|
do {
|
|
|
|
tmp = seconds;
|
|
|
|
} while(tmp != seconds);
|
|
|
|
return tmp;
|
2006-12-22 18:04:38 +01:00
|
|
|
}
|
2011-11-14 17:36:18 +01:00
|
|
|
#ifdef HANDLE_UNSUPPORTED_INTERRUPTS
|
|
|
|
/* Ignore unsupported interrupts, optionally hang for debugging */
|
2012-01-10 18:42:27 +01:00
|
|
|
/* BADISR is a gcc weak symbol that matches any undefined interrupt */
|
2011-11-14 17:36:18 +01:00
|
|
|
ISR(BADISR_vect) {
|
|
|
|
//static volatile uint8_t x;while (1) x++;
|
|
|
|
}
|
|
|
|
#endif
|
2011-03-13 19:08:02 +01:00
|
|
|
#ifdef HANG_ON_UNKNOWN_INTERRUPT
|
2011-11-14 17:36:18 +01:00
|
|
|
/* Hang on any unsupported interrupt */
|
2011-03-13 18:07:32 +01:00
|
|
|
/* Useful for diagnosing unknown interrupts that reset the mcu.
|
|
|
|
* Currently set up for 12mega128rfa1.
|
|
|
|
* For other mcus, enable all and then disable the conflicts.
|
|
|
|
*/
|
|
|
|
static volatile uint8_t x;
|
|
|
|
ISR( _VECTOR(0)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(1)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(2)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(3)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(4)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(5)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(6)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(7)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(8)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(9)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(10)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(11)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(12)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(13)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(14)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(15)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(16)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(17)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(18)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(19)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(20)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(21)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(22)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(23)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(24)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(25)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(26)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(27)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(28)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(29)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(30)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(31)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(32)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(33)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(34)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(35)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(36)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(37)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(38)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(39)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(40)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(41)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(42)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(43)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(44)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(45)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(46)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(47)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(48)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(49)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(50)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(51)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(52)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(53)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(54)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(55)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(56)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(57)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(58)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(59)) {while (1) x++;}
|
|
|
|
//ISR( _VECTOR(60)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(61)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(62)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(63)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(64)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(65)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(66)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(67)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(68)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(69)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(70)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(71)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(72)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(73)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(74)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(75)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(76)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(77)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(78)) {while (1) x++;}
|
|
|
|
ISR( _VECTOR(79)) {while (1) x++;}
|
2011-09-10 18:44:49 +02:00
|
|
|
#endif
|