From ad141b00fbb20a422a02c6f0ce5048f2cdaf7ae0 Mon Sep 17 00:00:00 2001 From: Jim Paris Date: Fri, 27 Jun 2014 18:19:05 -0400 Subject: [PATCH] Implement rtimers for ADuCRF101 --- cpu/arm/aducrf101/Makefile.aducrf101 | 1 + cpu/arm/aducrf101/aducrf101-contiki.h | 4 +- cpu/arm/aducrf101/rtimer-arch.c | 103 ++++++++++++++++++++--- cpu/arm/aducrf101/rtimer-arch.h | 2 +- platform/ev-aducrf101mkxz/contiki-main.c | 1 + 5 files changed, 96 insertions(+), 15 deletions(-) diff --git a/cpu/arm/aducrf101/Makefile.aducrf101 b/cpu/arm/aducrf101/Makefile.aducrf101 index a613fd28f..337da3385 100644 --- a/cpu/arm/aducrf101/Makefile.aducrf101 +++ b/cpu/arm/aducrf101/Makefile.aducrf101 @@ -101,6 +101,7 @@ CONTIKI_CPU_DIRS += ../common/CMSIS CONTIKI_CPU_DIRS += . CONTIKI_SOURCEFILES += slip-arch.c +CONTIKI_SOURCEFILES += rtimer-arch.c CONTIKI_CPU_DIRS += dev CONTIKI_SOURCEFILES += uart.c diff --git a/cpu/arm/aducrf101/aducrf101-contiki.h b/cpu/arm/aducrf101/aducrf101-contiki.h index f82231cba..00fd8765d 100644 --- a/cpu/arm/aducrf101/aducrf101-contiki.h +++ b/cpu/arm/aducrf101/aducrf101-contiki.h @@ -45,8 +45,8 @@ typedef uint32_t clock_time_t; typedef uint16_t uip_stats_t; -typedef unsigned long rtimer_clock_t; -#define RTIMER_CLOCK_LT(a, b) ((signed long)((a) - (b)) < 0) +typedef uint32_t rtimer_clock_t; +#define RTIMER_CLOCK_LT(a, b) ((int32_t)((a) - (b)) < 0) rtimer_clock_t rtimer_arch_now(void); #endif diff --git a/cpu/arm/aducrf101/rtimer-arch.c b/cpu/arm/aducrf101/rtimer-arch.c index 14518eb84..4f6b3caa3 100644 --- a/cpu/arm/aducrf101/rtimer-arch.c +++ b/cpu/arm/aducrf101/rtimer-arch.c @@ -35,25 +35,104 @@ * \author Jim Paris */ +#include #include "rtimer-arch.h" +#include "aducrf101-contiki.h" +/* rtimer on the ADuCRF101 is implemented with the "wakeup" timer. + (timer 2). It should be clocked from an external crystal, + but if that doesn't seem to be present, this code will select the + imprecise internal 32.768 KHz oscillator instead. */ + +static void +_timer2_enable(int enable) +{ + T2CON_ENABLE_BBA = enable; + clock_time_t now = clock_time(); + while(T2STA_CON_BBA) { + /* Synchronizing settings may fail if the chosen clock isn't running; + wait no more than 1ms for it */ + if((clock_time() - now) > (CLOCK_SECOND / 1000)) { + break; + } + } +} +static uint32_t +_timer2_val(void) +{ + /* This is atomic because the FREEZE bit is set in T2CON. */ + uint32_t now; + now = pADI_WUT->T2VAL0; + now |= pADI_WUT->T2VAL1 << 16; + return now; +} +static uint32_t +_timer2_measure_freq(void) +{ + const int test_usec = 10000; + uint32_t now = _timer2_val(); + clock_delay_usec(test_usec); + return (_timer2_val() - now) * (1000000 / test_usec); +} void rtimer_arch_init(void) { + uint32_t freq; + const char *timer = "LFXTAL"; + + _timer2_enable(0); + pADI_WUT->T2CON = T2CON_PRE_DIV1 | T2CON_MOD_FREERUN | T2CON_FREEZE_EN | + T2CON_WUEN_EN; + + /* Try 32.768 KHz crystal */ + pADI_WUT->T2CON |= T2CON_CLK_LFXTAL; + _timer2_enable(1); + freq = _timer2_measure_freq(); + + if(freq < 20000 || freq > 40000) { + /* No good; use 32.768 KHz internal oscillator */ + _timer2_enable(0); + pADI_WUT->T2CON &= ~T2CON_CLK_MSK; + pADI_WUT->T2CON |= T2CON_CLK_LFOSC; + _timer2_enable(1); + freq = _timer2_measure_freq(); + timer = "LFOSC"; + } + + printf("Using %s for rtimer (%ld Hz)\n", timer, freq); + + /* Enable interrupt in NVIC, but disable in WUT for now. */ + pADI_WUT->T2IEN = 0; + NVIC_EnableIRQ(WUT_IRQn); } -/*---------------------------------------------------------------------------*/ -void -rtimer_arch_schedule(rtimer_clock_t t) -{ -} -/*---------------------------------------------------------------------------*/ -void -rtimer_arch_set(rtimer_clock_t t) -{ -} -/*---------------------------------------------------------------------------*/ rtimer_clock_t rtimer_arch_now(void) { - return 0; + /* This is atomic because the FREEZE bit is set in T2CON. */ + return _timer2_val(); +} +void +rtimer_arch_schedule(rtimer_clock_t t) +{ + uint32_t now = _timer2_val(); + + /* Minimum of 5 wakeup timer ticks */ + if((int32_t)(t - now) < 5) { + t = now + 5; + } + + /* Set T2WUFB to match at target time */ + T2IEN_WUFB_BBA = 0; + pADI_WUT->T2WUFB0 = (t & 0xffff); + pADI_WUT->T2WUFB1 = (t >> 16); + T2IEN_WUFB_BBA = 1; +} +void +WakeUp_Int_Handler(void) +{ + /* clear interrupt */ + T2CLRI_WUFB_BBA = 1; + /* disable T2WUFB match */ + T2IEN_WUFB_BBA = 0; + rtimer_run_next(); } diff --git a/cpu/arm/aducrf101/rtimer-arch.h b/cpu/arm/aducrf101/rtimer-arch.h index 88399bd87..ec28dcf7d 100644 --- a/cpu/arm/aducrf101/rtimer-arch.h +++ b/cpu/arm/aducrf101/rtimer-arch.h @@ -40,7 +40,7 @@ #include -#define RTIMER_ARCH_SECOND (1000) +#define RTIMER_ARCH_SECOND (32768) #include "sys/rtimer.h" diff --git a/platform/ev-aducrf101mkxz/contiki-main.c b/platform/ev-aducrf101mkxz/contiki-main.c index 944e2d278..0dd4dee18 100644 --- a/platform/ev-aducrf101mkxz/contiki-main.c +++ b/platform/ev-aducrf101mkxz/contiki-main.c @@ -132,6 +132,7 @@ main(int argc, char **argv) process_init(); process_start(&etimer_process, NULL); ctimer_init(); + rtimer_init(); set_rime_addr();