Contiki-Inga 3.x
clock.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/
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  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /**
32  * \addtogroup cc2538
33  * @{
34  *
35  * \defgroup cc2538-clock cc2538 Clock
36  *
37  * Implementation of the clock module for the cc2538
38  *
39  * To implement the clock functionality, we use the SysTick peripheral on the
40  * cortex-M3. We run the system clock at 16 MHz and we set the SysTick to give
41  * us 128 interrupts / sec
42  * @{
43  *
44  * \file
45  * Clock driver implementation for the TI cc2538
46  */
47 #include "contiki.h"
48 #include "systick.h"
49 #include "reg.h"
50 #include "cpu.h"
51 #include "dev/gptimer.h"
52 #include "dev/sys-ctrl.h"
53 
54 #include "sys/energest.h"
55 
56 #include <stdint.h>
57 /*---------------------------------------------------------------------------*/
58 #define RELOAD_VALUE (125000 - 1) /** Fire 128 times / sec */
59 
60 static volatile clock_time_t count;
61 static volatile unsigned long secs = 0;
62 static volatile uint8_t second_countdown = CLOCK_SECOND;
63 /*---------------------------------------------------------------------------*/
64 /**
65  * \brief Arch-specific implementation of clock_init for the cc2538
66  *
67  * We initialise the SysTick to fire 128 interrupts per second, giving us a
68  * value of 128 for CLOCK_SECOND
69  *
70  * We also initialise GPT0:Timer A, which is used by clock_delay_usec().
71  * We use 16-bit range (individual), count-down, one-shot, no interrupts.
72  * The system clock is at 16MHz giving us 62.5 nano sec ticks for Timer A.
73  * Prescaled by 16 gives us a very convenient 1 tick per usec
74  */
75 void
77 {
78  count = 0;
79 
80  REG(SYSTICK_STRELOAD) = RELOAD_VALUE;
81 
82  /* System clock source, Enable */
83  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_CLK_SRC | SYSTICK_STCTRL_ENABLE;
84 
85  /* Enable the SysTick Interrupt */
86  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_INTEN;
87 
88  /*
89  * Remove the clock gate to enable GPT0 and then initialise it
90  * We only use GPT0 for clock_delay_usec. We initialise it here so we can
91  * have it ready when it's needed
92  */
94 
95  /* Make sure GPT0 is off */
96  REG(GPT_0_BASE | GPTIMER_CTL) = 0;
97 
98 
99  /* 16-bit */
100  REG(GPT_0_BASE | GPTIMER_CFG) = 0x04;
101 
102  /* One-Shot, Count Down, No Interrupts */
103  REG(GPT_0_BASE | GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
104 
105  /* Prescale by 16 (thus, value 15 in TAPR) */
106  REG(GPT_0_BASE | GPTIMER_TAPR) = 0x0F;
107 }
108 /*---------------------------------------------------------------------------*/
109 CCIF clock_time_t
111 {
112  return count;
113 }
114 /*---------------------------------------------------------------------------*/
115 void
116 clock_set_seconds(unsigned long sec)
117 {
118  secs = sec;
119 }
120 /*---------------------------------------------------------------------------*/
121 CCIF unsigned long
123 {
124  return secs;
125 }
126 /*---------------------------------------------------------------------------*/
127 void
128 clock_wait(clock_time_t i)
129 {
130  clock_time_t start;
131 
132  start = clock_time();
133  while(clock_time() - start < (clock_time_t)i);
134 }
135 /*---------------------------------------------------------------------------*/
136 /**
137  * \brief Arch-specific implementation of clock_delay_usec for the cc2538
138  * \param len Delay \e len uSecs
139  *
140  * See clock_init() for GPT0 Timer A's configuration
141  */
142 void
143 clock_delay_usec(uint16_t len)
144 {
145  REG(GPT_0_BASE | GPTIMER_TAILR) = len;
147 
148  /* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
149  while(REG(GPT_0_BASE | GPTIMER_CTL) & GPTIMER_CTL_TAEN);
150 }
151 /*---------------------------------------------------------------------------*/
152 /**
153  * \brief Obsolete delay function but we implement it here since some code
154  * still uses it
155  */
156 void
157 clock_delay(unsigned int i)
158 {
159  clock_delay_usec(i);
160 }
161 /*---------------------------------------------------------------------------*/
162 /**
163  * \brief Adjust the clock by moving it forward by a number of ticks
164  * \param ticks The number of ticks
165  *
166  * This function is useful when coming out of PM1/2, during which the system
167  * clock is stopped. We adjust the clock by moving it forward by a number of
168  * ticks equal to the deep sleep duration. We update the seconds counter if
169  * we have to and we also do some housekeeping so that the next second will
170  * increment when it is meant to.
171  *
172  * \note This function is only meant to be used by lpm_exit(). Applications
173  * should really avoid calling this
174  */
175 void
176 clock_adjust(clock_time_t ticks)
177 {
178  /* Halt the SysTick while adjusting */
179  REG(SYSTICK_STCTRL) &= ~SYSTICK_STCTRL_ENABLE;
180 
181  /* Moving forward by more than a second? */
182  secs += ticks >> 7;
183 
184  /* Increment tick count */
185  count += ticks;
186 
187  /*
188  * Update internal second countdown so that next second change will actually
189  * happen when it's meant to happen.
190  */
191  second_countdown -= ticks;
192 
193  if(second_countdown == 0 || second_countdown > 128) {
194  secs++;
195  second_countdown -= 128;
196  }
197 
198  /* Re-Start the SysTick */
199  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_ENABLE;
200 }
201 /*---------------------------------------------------------------------------*/
202 /**
203  * \brief The clock Interrupt Service Routine. It polls the etimer process
204  * if an etimer has expired. It also updates the software clock tick and
205  * seconds counter since reset.
206  */
207 void
209 {
210  ENERGEST_ON(ENERGEST_TYPE_IRQ);
211  count++;
212  if(etimer_pending()) {
214  }
215 
216  if(--second_countdown == 0) {
217  secs++;
218  second_countdown = CLOCK_SECOND;
219  }
220  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
221 }
222 /*---------------------------------------------------------------------------*/
223 
224 /**
225  * @}
226  * @}
227  */