Contiki 3.x
rtimer-arch-slow.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, SICS Swedish ICT.
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  * \file
35  * RTIMER for NXP jn516x: 32 kHz mode
36  * \author
37  * Atis Elsts <atis.elsts@sics.se>
38  */
39 
40 #include "sys/rtimer.h"
41 #include "sys/clock.h"
42 #include <AppHardwareApi.h>
43 #include <PeripheralRegs.h>
44 #include <MicroSpecific.h>
45 #include "dev/watchdog.h"
46 #include "sys/energest.h"
47 #include "sys/process.h"
48 
49 #if RTIMER_USE_32KHZ
50 
51 #define DEBUG 0
52 #if DEBUG
53 #include <stdio.h>
54 #define PRINTF(...) printf(__VA_ARGS__)
55 #else
56 #define PRINTF(...)
57 #endif
58 
59 #define RTIMER_TIMER_ISR_DEV E_AHI_DEVICE_SYSCTRL
60 /* 1.5 days wraparound time */
61 #define MAX_VALUE 0xFFFFFFFF
62 /* make this small to more easily detect wraparound bugs */
63 #define START_VALUE (60 * RTIMER_ARCH_SECOND)
64 #define WRAPAROUND_VALUE ((uint64_t)0x1FFFFFFFFFF)
65 
66 static volatile rtimer_clock_t scheduled_time;
67 static volatile uint8_t has_next;
68 
69 /*---------------------------------------------------------------------------*/
70 static void
71 timerISR(uint32 u32Device, uint32 u32ItemBitmap)
72 {
73  PRINTF("\ntimer isr %u %u\n", u32Device, u32ItemBitmap);
74  if(u32Device != RTIMER_TIMER_ISR_DEV) {
75  return;
76  }
77 
78  ENERGEST_ON(ENERGEST_TYPE_IRQ);
79 
80  if(u32ItemBitmap & TICK_TIMER_MASK) {
81  /* 32-bit overflow happened; restart the timer */
82  uint32_t ticks_late = WRAPAROUND_VALUE - u64AHI_WakeTimerReadLarge(TICK_TIMER);
83 
84  PRINTF("\nrtimer oflw, missed ticks %u\n", ticks_late);
85 
86  vAHI_WakeTimerStartLarge(TICK_TIMER, MAX_VALUE - ticks_late);
87  }
88 
89  if(u32ItemBitmap & WAKEUP_TIMER_MASK) {
90  PRINTF("\nrtimer fire @ %u\n", rtimer_arch_now());
91 
92  /* Compare with the current time, as after sleep there is
93  * a fake interrupt generated 10ms earlier to wake up & reinitialize
94  * the system before the actual rtimer fires.
95  */
96  rtimer_clock_t now = rtimer_arch_now();
97  if(RTIMER_CLOCK_LT(now + 1, scheduled_time)) {
98  vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
99  vAHI_WakeTimerStartLarge(WAKEUP_TIMER, scheduled_time - now);
100  } else {
101  has_next = 0;
102  watchdog_start();
103  rtimer_run_next();
104  process_nevents();
105  }
106  }
107 
108  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
109 }
110 /*---------------------------------------------------------------------------*/
111 void
112 rtimer_arch_init(void)
113 {
114  /* Initialise tick timer to run continuously */
115  vAHI_TickTimerIntEnable(0);
116  vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
117  vAHI_TickTimerWrite(0);
118  vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
119 
120  vAHI_SysCtrlRegisterCallback(timerISR);
121  /* set the highest priority for the rtimer interrupt */
122  vAHI_InterruptSetPriority(MICRO_ISR_MASK_SYSCTRL, 15);
123  /* enable interrupt on a rtimer */
124  vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
125  /* enable interrupt on 32-bit overflow */
126  vAHI_WakeTimerEnable(TICK_TIMER, TRUE);
127  /* count down from START_VALUE */
128  vAHI_WakeTimerStartLarge(TICK_TIMER, START_VALUE);
129 
130  (void)u32AHI_Init();
131 }
132 /*---------------------------------------------------------------------------*/
133 void
134 rtimer_arch_reinit(rtimer_clock_t sleep_start, rtimer_clock_t sleep_ticks)
135 {
136  uint64_t t;
137 
138  uint32_t wakeup_time = sleep_start + (uint64_t)sleep_ticks * (F_CPU / 2) / RTIMER_SECOND;
139 
140  /* Initialise tick timer to run continuously */
141  vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
142  vAHI_TickTimerIntEnable(0);
143  WAIT_FOR_EDGE(t);
144  vAHI_TickTimerWrite(wakeup_time);
145  vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
146 
147  /* call pending interrupts */
148  (void)u32AHI_Init();
149 
150  if(has_next) {
151  /* reschedule the timer */
152  rtimer_arch_schedule(scheduled_time);
153  }
154 }
155 /*---------------------------------------------------------------------------*/
156 rtimer_clock_t
157 rtimer_arch_now(void)
158 {
159  return START_VALUE - (rtimer_clock_t)u64AHI_WakeTimerReadLarge(TICK_TIMER);
160 }
161 /*---------------------------------------------------------------------------*/
162 void
163 rtimer_arch_schedule(rtimer_clock_t t)
164 {
165  PRINTF("rtimer_arch_schedule time %lu\n", t);
166  vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
167  vAHI_WakeTimerStartLarge(WAKEUP_TIMER, t - rtimer_arch_now());
168  scheduled_time = t;
169  has_next = 1;
170 }
171 /*---------------------------------------------------------------------------*/
172 rtimer_clock_t
173 rtimer_arch_time_to_rtimer(void)
174 {
175  rtimer_clock_t now = RTIMER_NOW();
176  if(has_next) {
177  return scheduled_time >= now ? scheduled_time - now : 0;
178  }
179  /* if no wakeup is scheduled yet return maximum time */
180  return (rtimer_clock_t)-1;
181 }
182 /*---------------------------------------------------------------------------*/
183 #endif /* RTIMER_USE_32KHZ */
#define TRUE
An alias for one, used for clarity.
void rtimer_arch_init(void)
We don't need to explicitly initialise anything but this routine is required by the API...
Definition: rtimer-arch.c:78
Header file for the real-time timer module.
void rtimer_arch_schedule(rtimer_clock_t t)
Schedules an rtimer task to be triggered at time t.
Definition: rtimer-arch.c:115
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
Header file for the energy estimation mechanism
#define rtimer_arch_now()
Definition: rtimer-arch.h:40
void rtimer_run_next(void)
Execute the next real-time task and schedule the next task, if any.
Definition: rtimer.c:92
Header file for the Contiki process interface.
int process_nevents(void)
Number of events waiting to be processed.
Definition: process.c:316
void watchdog_start(void)
Starts the WDT in watchdog mode if enabled by user configuration, maximum interval.
Definition: watchdog.c:49