From fb8bbf37cf4550ef2756d3e7bf3abdbd9e7688cb Mon Sep 17 00:00:00 2001 From: Mariano Alvira Date: Sun, 3 Feb 2013 14:50:30 -0500 Subject: [PATCH] Use the RTC only as the main timer. This is a major change to how the main tick interrupt is handled on the mc1322x platforms. Instead of using two timer resources, TMR0 and RTC, this patch unifies all the timers to use the RTC. This is enabled by implementing etimers as scheduled rtimers. The main advantage (aside from freeing TMR0 for general use) is have the Contiki timebase come from the same source that will be used for sleeping and wakeup. --- cpu/mc1322x/Makefile.mc1322x | 2 +- cpu/mc1322x/clock.c | 115 +++++++++------------------ cpu/mc1322x/contiki-crm.c | 121 ----------------------------- cpu/mc1322x/contiki-mc1322x-conf.h | 6 +- cpu/mc1322x/init.c | 9 ++- cpu/mc1322x/lib/rtc.c | 4 +- cpu/mc1322x/rtimer-arch.c | 92 +++++++++++++++++----- cpu/mc1322x/rtimer-arch.h | 8 +- platform/econotag/contiki-conf.h | 4 - 9 files changed, 128 insertions(+), 233 deletions(-) delete mode 100644 cpu/mc1322x/contiki-crm.c diff --git a/cpu/mc1322x/Makefile.mc1322x b/cpu/mc1322x/Makefile.mc1322x index 185077562..05f936439 100644 --- a/cpu/mc1322x/Makefile.mc1322x +++ b/cpu/mc1322x/Makefile.mc1322x @@ -10,7 +10,7 @@ CONTIKI_CPU=$(CONTIKI)/cpu/mc1322x CONTIKI_CPU_DIRS = . lib src board dev ../arm/common/dbg-io -MC1322X = debug-uart.c rtimer-arch.c watchdog.c contiki-crm.c contiki-maca.c contiki-misc.c leds-arch.c leds.c contiki-uart.c slip-uart1.c init.c config.c +MC1322X = debug-uart.c rtimer-arch.c watchdog.c contiki-maca.c contiki-misc.c leds-arch.c leds.c contiki-uart.c slip-uart1.c init.c config.c DBG_IO = dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/cpu/mc1322x/clock.c b/cpu/mc1322x/clock.c index e6990e731..611a90251 100644 --- a/cpu/mc1322x/clock.c +++ b/cpu/mc1322x/clock.c @@ -36,93 +36,52 @@ #include #include #include -#include "dev/leds.h" +#include #include "contiki-conf.h" #include "mc1322x.h" -#include "contiki-conf.h" - #define MAX_TICKS (~((clock_time_t)0) / 2) static volatile clock_time_t current_clock = 0; volatile unsigned long seconds = 0; -#define TCF 15 -#define TCF1 4 -#define TCF2 5 +static struct rtimer rt_clock; +/* the typical clock things like incrementing current_clock and etimer checks */ +/* are performed as a periodically scheduled rtimer */ void -clock_init() +rt_do_clock(struct rtimer *t, void *ptr) { - /* timer setup */ - /* CTRL */ -#define COUNT_MODE 1 /* use rising edge of primary source */ -#define PRIME_SRC 0xf /* Perip. clock with 128 prescale (for 24Mhz = 187500Hz)*/ -#define SEC_SRC 0 /* don't need this */ -#define ONCE 0 /* keep counting */ -#define LEN 1 /* count until compare then reload with value in LOAD */ -#define DIR 0 /* count up */ -#define CO_INIT 0 /* other counters cannot force a re-initialization of this counter */ -#define OUT_MODE 0 /* OFLAG is asserted while counter is active */ + rtimer_set(t, RTIMER_TIME(t) + (rtc_freq/CLOCK_CONF_SECOND) , 1, + (rtimer_callback_t)rt_do_clock, ptr); - *TMR_ENBL = 0; /* tmrs reset to enabled */ - *TMR0_SCTRL = 0; - *TMR0_CSCTRL =0x0040; - *TMR0_LOAD = 0; /* reload to zero */ - *TMR0_COMP_UP = 1875; /* trigger a reload at the end */ - *TMR0_CMPLD1 = 1875; /* compare 1 triggered reload level, 10HZ maybe? */ - *TMR0_CNTR = 0; /* reset count register */ - *TMR0_CTRL = (COUNT_MODE<<13) | (PRIME_SRC<<9) | (SEC_SRC<<7) | (ONCE<<6) | (LEN<<5) | (DIR<<4) | (CO_INIT<<3) | (OUT_MODE); - *TMR_ENBL = 0xf; /* enable all the timers --- why not? */ + current_clock++; + + if((current_clock % CLOCK_CONF_SECOND) == 0) { + seconds++; + } + + if(etimer_pending() && + (etimer_next_expiration_time() - current_clock - 1) > MAX_TICKS) { + etimer_request_poll(); + } - enable_irq(TMR); -/* Do startup scan of the ADC */ -#if CLOCK_CONF_SAMPLEADC - adc_reading[8]=0; - adc_init(); - while (adc_reading[8]==0) adc_service(); -#endif } -void tmr0_isr(void) { - if(bit_is_set(*TMR(0,CSCTRL),TCF1)) { - current_clock++; - if((current_clock % CLOCK_CONF_SECOND) == 0) { - seconds++; -#if BLINK_SECONDS - leds_toggle(LEDS_GREEN); -#endif -/* ADC can be serviced every tick or every second */ -#if CLOCK_CONF_SAMPLEADC > 1 - adc_service(); -#endif - } -#if CLOCK_CONF_SAMPLEADC == 1 - adc_service(); -#endif - if(etimer_pending() && - (etimer_next_expiration_time() - current_clock - 1) > MAX_TICKS) { - etimer_request_poll(); - } - - /* clear the compare flags */ - clear_bit(*TMR(0,SCTRL),TCF); - clear_bit(*TMR(0,CSCTRL),TCF1); - clear_bit(*TMR(0,CSCTRL),TCF2); - return; - } else { - /* this timer didn't create an interrupt condition */ - return; - } +/* RTC MUST have been already setup by mc1322x init */ +void +clock_init(void) +{ + rtimer_set(&rt_clock, RTIMER_NOW() + rtc_freq/CLOCK_CONF_SECOND, 1, (rtimer_callback_t)rt_do_clock, NULL); } clock_time_t clock_time(void) { - return current_clock; + return current_clock; } unsigned long @@ -134,8 +93,8 @@ clock_seconds(void) void clock_wait(clock_time_t t) { - clock_time_t endticks = current_clock + t; - while ((signed long)(current_clock - endticks) < 0) {;} + clock_time_t endticks = current_clock + t; + while ((signed long)(current_clock - endticks) < 0) {;} } /*---------------------------------------------------------------------------*/ /** @@ -146,17 +105,17 @@ clock_wait(clock_time_t t) void clock_delay_usec(uint16_t howlong) { - if(howlong<2) return; + if(howlong<2) return; #if 0 - if(howlong>400) { - volatile register uint32_t i=*MACA_CLK+howlong/4; - while (i > *MACA_CLK) ; - return; - } + if(howlong>400) { + volatile register uint32_t i=*MACA_CLK+howlong/4; + while (i > *MACA_CLK) ; + return; + } #endif - /* These numbers at 25MHz, gcc -Os */ - volatile register uint32_t i=4000*howlong/2301; - while(--i); + /* These numbers at 25MHz, gcc -Os */ + volatile register uint32_t i=4000*howlong/2301; + while(--i); } /*---------------------------------------------------------------------------*/ /** @@ -165,7 +124,7 @@ clock_delay_usec(uint16_t howlong) void clock_delay_msec(uint16_t howlong) { - while(howlong--) clock_delay_usec(1000); + while(howlong--) clock_delay_usec(1000); } /*---------------------------------------------------------------------------*/ /** @@ -176,8 +135,8 @@ clock_delay_msec(uint16_t howlong) void clock_delay(unsigned int howlong) { - if(howlong--) return; - clock_delay_usec((283*howlong)/100); + if(howlong--) return; + clock_delay_usec((283*howlong)/100); } /*---------------------------------------------------------------------------*/ /** diff --git a/cpu/mc1322x/contiki-crm.c b/cpu/mc1322x/contiki-crm.c deleted file mode 100644 index 41c36d679..000000000 --- a/cpu/mc1322x/contiki-crm.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2010, Mariano Alvira and other contributors - * to the MC1322x project (http://mc1322x.devl.org) and Contiki. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the Contiki OS. - * - * - */ - -#include "mc1322x.h" - -#define CRM_DEBUG 1 -#if CRM_DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - -uint32_t cal_rtc_secs; /* calibrated 2khz rtc seconds */ - -void sleep(uint32_t opts, uint32_t mode) -{ - - /* the maca must be off before going to sleep */ - /* otherwise the mcu will reboot on wakeup */ -// maca_off(); - *CRM_SLEEP_CNTL = opts; - *CRM_SLEEP_CNTL = (opts | mode); - - /* wait for the sleep cycle to complete */ - while(!bit_is_set(*CRM_STATUS,0)) { continue; } - /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and powers down */ - set_bit(*CRM_STATUS,0); - - /* now we are asleep */ - /* and waiting for something to wake us up */ - /* you did tell us how to wake up right? */ - - /* waking up */ - while(!bit_is_set(*CRM_STATUS,0)) { continue; } - /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and finishes the wakeup */ - set_bit(*CRM_STATUS,0); - - /* you may also need to do other recovery */ - /* such as interrupt handling */ - /* peripheral init */ - /* and turning the radio back on */ - -} - -/* turn on the 32kHz crystal */ -/* once you start the 32xHz crystal it can only be stopped with a reset (hard or soft) */ -void enable_32khz_xtal(void) -{ - static volatile uint32_t rtc_count; - PRINTF("enabling 32kHz crystal\n\r"); - /* first, disable the ring osc */ - ring_osc_off(); - /* enable the 32kHZ crystal */ - xtal32_on(); - - /* set the XTAL32_EXISTS bit */ - /* the datasheet says to do this after you've check that RTC_COUNT is changing */ - /* the datasheet is not correct */ - xtal32_exists(); - - /* now check that the crystal starts */ - /* this blocks until it starts */ - /* it would be better to timeout and return an error */ - rtc_count = *CRM_RTC_COUNT; - PRINTF("waiting for xtal\n\r"); - while(*CRM_RTC_COUNT == rtc_count) { - continue; - } - /* RTC has started up */ - PRINTF("32kHZ xtal started\n\r"); - -} - -void cal_ring_osc(void) -{ - uint32_t cal_factor; - PRINTF("performing ring osc cal\n\r"); - PRINTF("crm_status: 0x%0x\n\r",*CRM_STATUS); - PRINTF("sys_cntl: 0x%0x\n\r",*CRM_SYS_CNTL); - *CRM_CAL_CNTL = (1<<16) | (20000); - while((*CRM_STATUS & (1<<9)) == 0); - PRINTF("ring osc cal complete\n\r"); - PRINTF("cal_count: 0x%0x\n\r",*CRM_CAL_COUNT); - cal_factor = (REF_OSC*1000) / *CRM_CAL_COUNT; - cal_rtc_secs = (NOMINAL_RING_OSC_SEC * cal_factor)/100; - PRINTF("cal factor: %d\n\r", cal_factor); - PRINTF("hib_wake_secs: %d\n\r", cal_rtc_secs); - set_bit(*CRM_STATUS,9); -} diff --git a/cpu/mc1322x/contiki-mc1322x-conf.h b/cpu/mc1322x/contiki-mc1322x-conf.h index da8f6582a..b88331413 100644 --- a/cpu/mc1322x/contiki-mc1322x-conf.h +++ b/cpu/mc1322x/contiki-mc1322x-conf.h @@ -55,4 +55,8 @@ typedef unsigned short uip_stats_t; typedef uint32_t clock_time_t; -#endif \ No newline at end of file +/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_LT is defined */ +typedef unsigned long rtimer_clock_t; +#define RTIMER_CLOCK_LT(a,b) ((signed long)((a)-(b)) < 0) + +#endif diff --git a/cpu/mc1322x/init.c b/cpu/mc1322x/init.c index 00019c407..c14b3f9ea 100644 --- a/cpu/mc1322x/init.c +++ b/cpu/mc1322x/init.c @@ -102,6 +102,7 @@ void buck_setup(void) { CRM->VREG_CNTLbits.VREG_1P5V_SEL = 3; CRM->VREG_CNTLbits.VREG_1P5V_EN = 3; CRM->VREG_CNTLbits.VREG_1P8V_EN = 1; + while(CRM->STATUSbits.VREG_1P5V_RDY == 0) { continue; } while(CRM->STATUSbits.VREG_1P8V_RDY == 0) { continue; } @@ -149,6 +150,7 @@ void rtc_setup(void) { PRINTF("RTC calibrated to %d Hz\r\n", rtc_freq); } else { PRINTF("32kHz xtal started\n\r"); + rtc_freq = 32768; } } @@ -167,13 +169,11 @@ void mc1322x_init(void) { PRINTF("mc1322x init\n\r"); adc_init(); - clock_init(); ctimer_init(); process_init(); process_start(&etimer_process, NULL); process_start(&contiki_maca_process, NULL); buck_setup(); - rtc_setup(); /* start with a default config */ @@ -196,6 +196,11 @@ void mc1322x_init(void) { set_demodulator_type(mc1322x_config.flags.demod); set_prm_mode(mc1322x_config.flags.autoack); + /* must be done AFTER maca_init */ + /* the radio calibration appears to clobber the RTC trim caps */ + rtc_setup(); + rtimer_init(); + clock_init(); } diff --git a/cpu/mc1322x/lib/rtc.c b/cpu/mc1322x/lib/rtc.c index 7387352a9..1b69b5215 100644 --- a/cpu/mc1322x/lib/rtc.c +++ b/cpu/mc1322x/lib/rtc.c @@ -72,7 +72,7 @@ void rtc_init_osc(int use_32khz) continue; /* RTC has started up */ - rtc_freq = 32000; + rtc_freq = 32768; } else { @@ -168,7 +168,7 @@ void rtc_calibrate(void) uint32_t count; if (__use_32khz) { - rtc_freq = 32000; + rtc_freq = 32768; return; } diff --git a/cpu/mc1322x/rtimer-arch.c b/cpu/mc1322x/rtimer-arch.c index f85fb15a2..c62092a75 100644 --- a/cpu/mc1322x/rtimer-arch.c +++ b/cpu/mc1322x/rtimer-arch.c @@ -57,18 +57,41 @@ #define PRINTF(...) #endif -void rtc_isr(void) { - PRINTF("rtc_wu_irq\n\r"); - PRINTF("now is %u\n", rtimer_arch_now()); - disable_rtc_wu(); - disable_rtc_wu_irq(); +static uint32_t last_rtc; + +void +rtc_isr(void) +{ + /* see note in table 5-13 of the reference manual: it takes at least two RTC clocks for the EVT bit to clear */ + if ((CRM->RTC_COUNT - last_rtc) <= 2) { + CRM->STATUS = ~0; /* Clear all events */ + +// CRM->STATUSbits.RTC_WU_EVT = 1; + return; + } + + last_rtc = CRM->RTC_COUNT; + + /* Clear all events (for paranoia) */ + /* clear RTC event flag (for paranoia)*/ +// CRM->STATUSbits.RTC_WU_EVT = 1; + CRM->STATUS = ~0; + rtimer_run_next(); - clear_rtc_wu_evt(); + } void rtimer_arch_init(void) { + last_rtc = CRM->RTC_COUNT; + /* enable timeout interrupts */ + /* RTC WU is the periodic RTC timer */ + /* TIMER WU is the wakeup timers (clocked from the RTC source) */ + /* it does not appear you can have both enabled at the same time */ + CRM->WU_CNTLbits.RTC_WU_EN = 1; + CRM->WU_CNTLbits.RTC_WU_IEN = 1; + enable_irq(CRM); } void @@ -76,23 +99,52 @@ rtimer_arch_schedule(rtimer_clock_t t) { volatile uint32_t now; now = rtimer_arch_now(); - PRINTF("rtimer_arch_schedule time %u; now is %u\n", t,now); + PRINTF("rtimer_arch_schedule time %u; now is %u\n", t, now); -#if 1 -/* If specified time is always in the future, counter can wrap without harm */ - *CRM_RTC_TIMEOUT = t - now; -#else /* Immediate interrupt if specified time is before current time. This may also happen on counter overflow. */ - if(now>t) { - *CRM_RTC_TIMEOUT = 1; + if(now > t) { + CRM->RTC_TIMEOUT = 1; } else { - *CRM_RTC_TIMEOUT = t - now; + CRM->RTC_TIMEOUT = t - now; } -#endif - - clear_rtc_wu_evt(); - enable_rtc_wu(); - enable_rtc_wu_irq(); - PRINTF("rtimer_arch_schedule CRM_RTC_TIMEOUT is %u\n", *CRM_RTC_TIMEOUT); } + +void +rtimer_arch_sleep(rtimer_clock_t howlong) +{ + CRM->WU_CNTLbits.TIMER_WU_EN = 1; + CRM->WU_CNTLbits.RTC_WU_EN = 0; + CRM->WU_TIMEOUT = howlong; + + /* the maca must be off before going to sleep */ + /* otherwise the mcu will reboot on wakeup */ + maca_off(); + + CRM->SLEEP_CNTLbits.DOZE = 0; + CRM->SLEEP_CNTLbits.RAM_RET = 3; + CRM->SLEEP_CNTLbits.MCU_RET = 1; + CRM->SLEEP_CNTLbits.DIG_PAD_EN = 1; + CRM->SLEEP_CNTLbits.HIB = 1; + + /* wait for the sleep cycle to complete */ + while((*CRM_STATUS & 0x1) == 0) { continue; } + /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and powers down */ + *CRM_STATUS = 1; + + /* asleep */ + + /* wait for the awake cycle to complete */ + while((*CRM_STATUS & 0x1) == 0) { continue; } + /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and finishes wakeup */ + *CRM_STATUS = 1; + + CRM->WU_CNTLbits.TIMER_WU_EN = 0; + CRM->WU_CNTLbits.RTC_WU_EN = 1; + + /* reschedule clock ticks */ + clock_init(); + clock_adjust_ticks((CRM->WU_COUNT*CLOCK_CONF_SECOND)/rtc_freq); +} + + diff --git a/cpu/mc1322x/rtimer-arch.h b/cpu/mc1322x/rtimer-arch.h index 3b4e932de..2e8f4acce 100644 --- a/cpu/mc1322x/rtimer-arch.h +++ b/cpu/mc1322x/rtimer-arch.h @@ -47,15 +47,15 @@ #include "sys/rtimer.h" /* mc1322x */ -#include "crm.h" -#include "utils.h" +#include "mc1322x.h" #if USE_32KHZ_XTAL #define RTIMER_ARCH_SECOND 32768 #else -#define RTIMER_ARCH_SECOND 18778 /* close --- should get calibrated */ +#define RTIMER_ARCH_SECOND 2000 #endif -#define rtimer_arch_now() (*CRM_RTC_COUNT) +#define rtimer_arch_now() (CRM->RTC_COUNT) + #endif /* __RTIMER_ARCH_H__ */ diff --git a/platform/econotag/contiki-conf.h b/platform/econotag/contiki-conf.h index f4de30e5f..11bf24221 100644 --- a/platform/econotag/contiki-conf.h +++ b/platform/econotag/contiki-conf.h @@ -106,10 +106,6 @@ #define PLATFORM_HAS_LEDS 1 #define PLATFORM_HAS_BUTTON 1 -/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_LT is defined */ -typedef unsigned long rtimer_clock_t; -#define RTIMER_CLOCK_LT(a,b) ((signed long)((a)-(b)) < 0) - #define RIMEADDR_CONF_SIZE 8 #if WITH_UIP6